diff --git a/gap.go b/gap.go index 8190fb6..2f1d8b6 100644 --- a/gap.go +++ b/gap.go @@ -137,6 +137,7 @@ type GAPDevice interface { RequestConnectionParams(params ConnectionParams) error Connected() (bool, error) Disconnect() error + OpenL2CAPChannel(psm L2CAPPSM) (*L2CAPConn, error) } // ScanResult contains information from when an advertisement packet was diff --git a/gap_darwin.go b/gap_darwin.go index 02fd438..95f6b96 100644 --- a/gap_darwin.go +++ b/gap_darwin.go @@ -101,7 +101,8 @@ type deviceInternal struct { servicesChan chan error charsChan chan error - services map[UUID]DeviceService + services map[UUID]DeviceService + l2capChan chan l2capResult } // Connect starts a connection attempt to the given peripheral device address. @@ -257,6 +258,13 @@ func (pd *peripheralDelegate) DidWriteValueForCharacteristic(_ cbgo.Peripheral, } } +// DidOpenL2CAPChannel is called when an L2CAP channel has been opened. +func (pd *peripheralDelegate) DidOpenL2CAPChannel(prph cbgo.Peripheral, channel cbgo.L2CAPChannel, err error) { + if pd.d.l2capChan != nil { + pd.d.l2capChan <- l2capResult{channel: channel, err: err} + } +} + // DidUpdateNotificationState is called when the notification state for a characteristic // has been updated. It reports whether enabling/disabling notifications succeeded. func (pd *peripheralDelegate) DidUpdateNotificationState(prph cbgo.Peripheral, chr cbgo.Characteristic, err error) { diff --git a/go.mod b/go.mod index b63311e..bb4ddf8 100644 --- a/go.mod +++ b/go.mod @@ -7,8 +7,8 @@ require ( github.com/godbus/dbus/v5 v5.1.0 github.com/saltosystems/winrt-go v0.0.0-20260317170058-9c2fec580d96 github.com/soypat/cyw43439 v0.1.0 - github.com/tinygo-org/cbgo v0.0.4 - golang.org/x/crypto v0.12.0 + github.com/tinygo-org/cbgo v0.0.5-0.20260404133704-78b73a9c8e7e + golang.org/x/crypto v0.26.0 tinygo.org/x/drivers v0.33.0 tinygo.org/x/tinyfont v0.6.0 tinygo.org/x/tinyterm v0.5.0 @@ -21,6 +21,6 @@ require ( github.com/soypat/seqs v0.0.0-20250124201400-0d65bc7c1710 // indirect github.com/tinygo-org/pio v0.2.0 // indirect golang.org/x/exp v0.0.0-20241204233417-43b7b7cde48d // indirect - golang.org/x/sys v0.11.0 // indirect - golang.org/x/term v0.11.0 // indirect + golang.org/x/sys v0.23.0 // indirect + golang.org/x/term v0.23.0 // indirect ) diff --git a/go.sum b/go.sum index f5696cf..a19f696 100644 --- a/go.sum +++ b/go.sum @@ -5,6 +5,7 @@ github.com/go-ole/go-ole v1.2.6 h1:/Fpf6oFPoeFik9ty7siob0G6Ke8QvQEuVcuChpwXzpY= github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0= github.com/godbus/dbus/v5 v5.1.0 h1:4KLkAxT3aOY8Li4FRJe/KvhoNFFxo0m6fNuFUO8QJUk= github.com/godbus/dbus/v5 v5.1.0/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= +github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 h1:El6M4kTTCOh6aBiKaUGG7oYTSPP8MxqL4YI3kZKwcP4= github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510/go.mod h1:pupxD2MaaD3pAXIBCelhxNneeOaAeabZDe5s4K6zSpQ= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= @@ -26,21 +27,81 @@ github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXf github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.5 h1:s5PTfem8p8EbKQOctVV53k6jCJt3UX4IEJzwh+C324Q= github.com/stretchr/testify v1.7.5/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= -github.com/tinygo-org/cbgo v0.0.4 h1:3D76CRYbH03Rudi8sEgs/YO0x3JIMdyq8jlQtk/44fU= -github.com/tinygo-org/cbgo v0.0.4/go.mod h1:7+HgWIHd4nbAz0ESjGlJ1/v9LDU1Ox8MGzP9mah/fLk= +github.com/tinygo-org/cbgo v0.0.5-0.20260404133704-78b73a9c8e7e h1:6rWS9GYjNL5fM9R57DO9sm0k29i0083HhSfJCzEmq2Q= +github.com/tinygo-org/cbgo v0.0.5-0.20260404133704-78b73a9c8e7e/go.mod h1:FruLOLNWPVyKyydTExa3RiPBjlAiorVsfRizhv4evoM= github.com/tinygo-org/pio v0.2.0 h1:vo3xa6xDZ2rVtxrks/KcTZHF3qq4lyWOntvEvl2pOhU= github.com/tinygo-org/pio v0.2.0/go.mod h1:LU7Dw00NJ+N86QkeTGjMLNkYcEYMor6wTDpTCu0EaH8= -golang.org/x/crypto v0.12.0 h1:tFM/ta59kqch6LlvYnPa0yx5a83cL2nHflFhYKvv9Yk= -golang.org/x/crypto v0.12.0/go.mod h1:NF0Gs7EO5K4qLn+Ylc+fih8BSTeIjAP05siRnAh98yw= +github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc= +golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU= +golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8= +golang.org/x/crypto v0.26.0 h1:RrRspgV4mU+YwB4FYnuBoKsUapNIL5cohGAmSH3azsw= +golang.org/x/crypto v0.26.0/go.mod h1:GY7jblb9wI+FOo5y8/S2oY4zWP07AkOJ4+jxCqdqn54= golang.org/x/exp v0.0.0-20241204233417-43b7b7cde48d h1:0olWaB5pg3+oychR51GUVCEsGkeCU/2JxjBgIo4f3M0= golang.org/x/exp v0.0.0-20241204233417-43b7b7cde48d/go.mod h1:qj5a5QZpwLU2NLQudwIN5koi3beDhSAlJwa67PuM98c= +golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= +golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= +golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= +golang.org/x/mod v0.15.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= +golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= +golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= +golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= +golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk= +golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44= +golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= +golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.11.0 h1:eG7RXZHdqOJ1i+0lgLgCpSXAp6M3LYlAo6osgSi0xOM= -golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/term v0.11.0 h1:F9tnn/DA/Im8nCwm+fX+1/eBwi4qFjRT++MhtVC4ZX0= -golang.org/x/term v0.11.0/go.mod h1:zC9APTIj3jG3FdV/Ons+XE1riIZXG4aZ4GTHiPZJPIU= +golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.23.0 h1:YfKFowiIMvtgl1UERQoTPPToxltDeZfbj4H7dVUCwmM= +golang.org/x/sys v0.23.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/telemetry v0.0.0-20240228155512-f48c80bd79b2/go.mod h1:TeRTkGYfJXctD9OcfyVLyj2J3IxLnKwHJR8f4D8a3YE= +golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= +golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= +golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo= +golang.org/x/term v0.12.0/go.mod h1:owVbMEjm3cBLCHdkQu9b1opXd4ETQWc3BhuQGKgXgvU= +golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk= +golang.org/x/term v0.20.0/go.mod h1:8UkIAJTvZgivsXaD6/pH6U9ecQzZ45awqEOzuCvwpFY= +golang.org/x/term v0.23.0 h1:F6D4vR+EHoL9/sWAWgAR1H2DcHr4PareCbAaCo1RpuU= +golang.org/x/term v0.23.0/go.mod h1:DgV24QBUrK6jhZXl+20l6UWznPlwAHm1Q1mGHtydmSk= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= +golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= +golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= +golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= +golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= +golang.org/x/text v0.17.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= +golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= +golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58= +golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= diff --git a/l2cap.go b/l2cap.go new file mode 100644 index 0000000..227b33c --- /dev/null +++ b/l2cap.go @@ -0,0 +1,13 @@ +package bluetooth + +import "io" + +// L2CAPPSM represents an L2CAP Protocol/Service Multiplexer identifier. +type L2CAPPSM = uint16 + +// L2CAPChannel is the common interface implemented by L2CAPConn on all platforms. +type L2CAPChannel interface { + io.ReadWriteCloser + // PSM returns the Protocol/Service Multiplexer identifier for this channel. + PSM() L2CAPPSM +} diff --git a/l2cap_darwin.go b/l2cap_darwin.go new file mode 100644 index 0000000..5fe8101 --- /dev/null +++ b/l2cap_darwin.go @@ -0,0 +1,143 @@ +package bluetooth + +import ( + "errors" + "io" + "runtime" + "sync" + "time" + + "github.com/tinygo-org/cbgo" +) + +// l2capResult is used internally to communicate the result of an L2CAP channel +// open operation from the delegate callback to the calling goroutine. +type l2capResult struct { + channel cbgo.L2CAPChannel + err error +} + +// L2CAPConn represents an L2CAP Connection-Oriented Channel connection. +// It implements io.ReadWriteCloser for bidirectional communication. +type L2CAPConn struct { + channel cbgo.L2CAPChannel + mu sync.Mutex + closed bool +} + +var _ L2CAPChannel = (*L2CAPConn)(nil) + +// OpenL2CAPChannel opens an L2CAP Connection-Oriented Channel to the +// connected peripheral. The PSM (Protocol/Service Multiplexer) identifies the +// L2CAP service to connect to on the remote device. +// +// The device must already be connected via Connect before calling this method. +func (d Device) OpenL2CAPChannel(psm L2CAPPSM) (*L2CAPConn, error) { + ch := make(chan l2capResult, 1) + d.l2capChan = ch + defer func() { d.l2capChan = nil }() + + d.prph.OpenL2CAPChannel(psm) + + select { + case result := <-ch: + if result.err != nil { + return nil, result.err + } + return &L2CAPConn{ + channel: result.channel, + }, nil + case <-time.NewTimer(30 * time.Second).C: + return nil, errors.New("bluetooth: timeout on OpenL2CAPChannel") + } +} + +// Read reads data from the L2CAP channel. It blocks until data is available, +// the channel is closed locally, or the remote end closes the stream (EOF). +func (c *L2CAPConn) Read(p []byte) (int, error) { + if len(p) == 0 { + return 0, nil + } + + for { + c.mu.Lock() + if c.closed { + c.mu.Unlock() + return 0, io.ErrClosedPipe + } + c.mu.Unlock() + + n := c.channel.Read(p) + if n < 0 { + return 0, errors.New("bluetooth: L2CAP read error") + } + if n > 0 { + return n, nil + } + + // c.channel.Read returns 0 in two cases: + // - hasBytesAvailable was false → no data yet, retry. + // - hasBytesAvailable was true but NSInputStream read returned 0 → EOF. + // Distinguish them by checking HasBytesAvailable after a 0-byte read. + if !c.channel.HasBytesAvailable() { + // No data available yet, yield and retry. + runtime.Gosched() + continue + } + // The stream reported bytes available yet Read returned 0: + // the input stream has reached end-of-stream. + return 0, io.EOF + } +} + +// Write writes data to the L2CAP channel. It blocks until all data has been +// written or the channel is closed. +func (c *L2CAPConn) Write(p []byte) (int, error) { + if len(p) == 0 { + return 0, nil + } + + total := 0 + for total < len(p) { + c.mu.Lock() + if c.closed { + c.mu.Unlock() + return total, io.ErrClosedPipe + } + c.mu.Unlock() + + // Output stream not ready yet, yield and retry. + if !c.channel.HasSpaceAvailable() { + runtime.Gosched() + continue + } + + n := c.channel.Write(p[total:]) + if n < 0 { + return total, errors.New("bluetooth: L2CAP write error") + } + if n > 0 { + total += n + continue + } + } + return total, nil +} + +// Close closes the L2CAP channel. +func (c *L2CAPConn) Close() error { + c.mu.Lock() + defer c.mu.Unlock() + + if c.closed { + return nil + } + c.closed = true + c.channel.Close() + return nil +} + +// PSM returns the Protocol/Service Multiplexer identifier for this channel. +func (c *L2CAPConn) PSM() L2CAPPSM { + return c.channel.PSM() +} diff --git a/l2cap_hci.go b/l2cap_hci.go index c4267ff..7995f91 100644 --- a/l2cap_hci.go +++ b/l2cap_hci.go @@ -164,3 +164,33 @@ func (l *l2cap) sendReq(handle uint16, data []byte) error { return l.hci.sendAclPkt(handle, signalingCID, data) } + +// L2CAPConn represents an L2CAP Connection-Oriented Channel connection. +type L2CAPConn struct{} + +var _ L2CAPChannel = (*L2CAPConn)(nil) + +// Read is not yet implemented on this platform. +func (c *L2CAPConn) Read(p []byte) (int, error) { + return 0, errNotYetImplmented +} + +// Write is not yet implemented on this platform. +func (c *L2CAPConn) Write(p []byte) (int, error) { + return 0, errNotYetImplmented +} + +// Close is not yet implemented on this platform. +func (c *L2CAPConn) Close() error { + return errNotYetImplmented +} + +// PSM is not yet implemented on this platform. +func (c *L2CAPConn) PSM() L2CAPPSM { + return 0 +} + +// OpenL2CAPChannel is not yet implemented on this platform. +func (d Device) OpenL2CAPChannel(psm L2CAPPSM) (*L2CAPConn, error) { + return nil, errNotYetImplmented +} diff --git a/l2cap_linux.go b/l2cap_linux.go new file mode 100644 index 0000000..0c46b09 --- /dev/null +++ b/l2cap_linux.go @@ -0,0 +1,33 @@ +//go:build !baremetal + +package bluetooth + +// L2CAPConn represents an L2CAP Connection-Oriented Channel connection. +type L2CAPConn struct{} + +var _ L2CAPChannel = (*L2CAPConn)(nil) + +// Read is not yet implemented on this platform. +func (c *L2CAPConn) Read(p []byte) (int, error) { + return 0, errNotYetImplmented +} + +// Write is not yet implemented on this platform. +func (c *L2CAPConn) Write(p []byte) (int, error) { + return 0, errNotYetImplmented +} + +// Close is not yet implemented on this platform. +func (c *L2CAPConn) Close() error { + return errNotYetImplmented +} + +// PSM is not yet implemented on this platform. +func (c *L2CAPConn) PSM() L2CAPPSM { + return 0 +} + +// OpenL2CAPChannel is not yet implemented on this platform. +func (d Device) OpenL2CAPChannel(psm L2CAPPSM) (*L2CAPConn, error) { + return nil, errNotYetImplmented +} diff --git a/l2cap_sd.go b/l2cap_sd.go new file mode 100644 index 0000000..ceb8a51 --- /dev/null +++ b/l2cap_sd.go @@ -0,0 +1,33 @@ +//go:build softdevice + +package bluetooth + +// L2CAPConn represents an L2CAP Connection-Oriented Channel connection. +type L2CAPConn struct{} + +var _ L2CAPChannel = (*L2CAPConn)(nil) + +// Read is not yet implemented on this platform. +func (c *L2CAPConn) Read(p []byte) (int, error) { + return 0, errNotYetImplmented +} + +// Write is not yet implemented on this platform. +func (c *L2CAPConn) Write(p []byte) (int, error) { + return 0, errNotYetImplmented +} + +// Close is not yet implemented on this platform. +func (c *L2CAPConn) Close() error { + return errNotYetImplmented +} + +// PSM is not yet implemented on this platform. +func (c *L2CAPConn) PSM() L2CAPPSM { + return 0 +} + +// OpenL2CAPChannel is not yet implemented on this platform. +func (d Device) OpenL2CAPChannel(psm L2CAPPSM) (*L2CAPConn, error) { + return nil, errNotYetImplmented +} diff --git a/l2cap_windows.go b/l2cap_windows.go new file mode 100644 index 0000000..70fc169 --- /dev/null +++ b/l2cap_windows.go @@ -0,0 +1,31 @@ +package bluetooth + +// L2CAPConn represents an L2CAP Connection-Oriented Channel connection. +type L2CAPConn struct{} + +var _ L2CAPChannel = (*L2CAPConn)(nil) + +// Read is not yet implemented on this platform. +func (c *L2CAPConn) Read(p []byte) (int, error) { + return 0, errNotYetImplmented +} + +// Write is not yet implemented on this platform. +func (c *L2CAPConn) Write(p []byte) (int, error) { + return 0, errNotYetImplmented +} + +// Close is not yet implemented on this platform. +func (c *L2CAPConn) Close() error { + return errNotYetImplmented +} + +// PSM is not yet implemented on this platform. +func (c *L2CAPConn) PSM() L2CAPPSM { + return 0 +} + +// OpenL2CAPChannel is not yet implemented on this platform. +func (d Device) OpenL2CAPChannel(psm L2CAPPSM) (*L2CAPConn, error) { + return nil, errNotYetImplmented +}