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

Write long characteristic #83

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions client.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,9 @@ type Client interface {
// WriteCharacteristic writes a characteristic value to a server. [Vol 3, Part G, 4.9.3]
WriteCharacteristic(c *Characteristic, value []byte, noRsp bool) error

// WriteLongCharacteristic writes a characteristic value that is longer than the MTU to a server. [Vol 3, Part F, 3.4.6]
WriteLongCharacteristic(c *Characteristic, value []byte) error

// ReadDescriptor reads a characteristic descriptor from a server. [Vol 3, Part G, 4.12.1]
ReadDescriptor(d *Descriptor) ([]byte, error)

Expand Down
5 changes: 5 additions & 0 deletions darwin/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -256,6 +256,11 @@ func (cln *Client) WriteCharacteristic(c *ble.Characteristic, b []byte, noRsp bo
return nil
}

// WriteLongCharacteristic writes a characteristic value that is longer than the MTU to a server. [Vol 3, Part F, 3.4.6]
func (cln *Client) WriteLongCharacteristic(c *ble.Characteristic, b []byte) error {
panic("not implemented")

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Rather than panic, this should return an error. Forcing a panic upon a calling program is bit jarring for the caller to deal with.

}

// ReadDescriptor reads a characteristic descriptor from a server. [Vol 3, Part G, 4.12.1]
func (cln *Client) ReadDescriptor(d *ble.Descriptor) ([]byte, error) {
cbdsc, err := cln.pc.findCbDsc(d)
Expand Down
3 changes: 2 additions & 1 deletion linux/att/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -422,6 +422,7 @@ func (c *Client) PrepareWrite(handle uint16, offset uint16, value []byte) (uint1
req.SetAttributeOpcode()
req.SetAttributeHandle(handle)
req.SetValueOffset(offset)
req.SetPartAttributeValue(value)

b, err := c.sendReq(req)
if err != nil {
Expand Down Expand Up @@ -452,7 +453,7 @@ func (c *Client) ExecuteWrite(flags uint8) error {
txBuf := <-c.chTxBuf
defer func() { c.chTxBuf <- txBuf }()

req := ExecuteWriteRequest(txBuf[:1])
req := ExecuteWriteRequest(txBuf[:2])
req.SetAttributeOpcode()
req.SetFlags(flags)

Expand Down
27 changes: 27 additions & 0 deletions linux/gatt/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -252,6 +252,26 @@ func (p *Client) WriteCharacteristic(c *ble.Characteristic, v []byte, noRsp bool
return p.ac.Write(c.ValueHandle, v)
}

// WriteLongCharacteristic writes a characteristic value that is longer than the MTU to a server. [Vol 3, Part F, 3.4.6]
func (p *Client) WriteLongCharacteristic(c *ble.Characteristic, v []byte) error {
p.Lock()
defer p.Unlock()

offset := 0
prepareWriteLength := 0

for offset < len(v) {
prepareWriteLength = MinInt( len(v) - offset, p.conn.TxMTU()-5 )

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Adding a function here adds a bit of complexity when an if would suffice. Since MinInt isn't used anywhere else, I don't see that it adds much value at this time. Additionally, I'd have to go review the spec to see recall why 5 is subtracted from the MTU here. I suspect it is overhead related. Please add a const which clarifies the reason for the subtraction.

Suggestion:

maxLength := p.conn.TxMTU() - 5

for offset < len(v) {
    length := len(v) - offset
    if length > maxLength {
        length = maxLength
    }

    value := v[offset:offset+length]
    ...

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You could also avoid having to track offset just by advancing v:

maxLength := p.conn.TxMTU() - 5
for len(v) > 0 {
    length := len(v)
    if length > maxLength {
        length = maxLength
    }
    ...
    v = v[length:]
}

value := v[offset:offset+prepareWriteLength]
if _, _, _, err := p.ac.PrepareWrite(c.ValueHandle, uint16(offset), value ); err != nil {
return err
}
offset += prepareWriteLength
}

return p.ac.ExecuteWrite(0x01) // flags: 0x00=cancel all, 0x01=write all
}

// ReadDescriptor reads a characteristic descriptor from a server. [Vol 3, Part G, 4.12.1]
func (p *Client) ReadDescriptor(d *ble.Descriptor) ([]byte, error) {
p.Lock()
Expand Down Expand Up @@ -401,3 +421,10 @@ type sub struct {
nHandler ble.NotificationHandler
iHandler ble.NotificationHandler
}

func MinInt( a int, b int) int {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you are ok with my suggestion above, this function can be removed.

if a < b {
return a
}
return b
}