Skip to content

Conversation

acouvreur
Copy link

@acouvreur acouvreur commented Oct 4, 2025

bluetooth/gattc_darwin.go

Lines 200 to 208 in 5c61529

// WriteWithoutResponse replaces the characteristic value with a new value. The
// call will return before all data has been written. A limited number of such
// writes can be in flight at any given time. This call is also known as a
// "write command" (as opposed to a write request).
func (c DeviceCharacteristic) WriteWithoutResponse(p []byte) (n int, err error) {
c.service.device.prph.WriteCharacteristic(p, c.characteristic, false)
return len(p), nil
}

A limited number of such writes can be in flight at any given time.

We should be able to use CanSendWriteWithoutResponse in gattc_darwin.go to know if we can send another write without response command.

Otherwise, write without response commands are failing silently (maybe the WriteWithoutResponse command should call CanSendWriteWithoutResponse instead and fail if it returns false ?)


I'm not sure if this is relevant in other OS


Example usage:

for i = 0; i < total; i+=chunkSize {
	end := i + chunkSize
	if end > total {
		end = total
	}

	for !rx.CanSendWriteWithoutResponse() {
		// Wait until we can send more data
		println("Waiting to send data... CanSendWriteWithoutResponse=false")
		time.Sleep(10 * time.Millisecond)
	}

	_, err = rx.WriteWithoutResponse(buf[i:end])
	if err != nil {
		println("Failed to write to RX characteristic:", err.Error())
		return
	}
	fmt.Printf("Sent %d/%d bytes\r", end, len(buf))
}

@HattoriHanzo031
Copy link
Contributor

HattoriHanzo031 commented Oct 12, 2025

I think you should rebase on dev, not release
https://github.com/tinygo-org/bluetooth/blob/release/CONTRIBUTING.md

@acouvreur acouvreur changed the base branch from release to dev October 12, 2025 21:24
@acouvreur
Copy link
Author

I think you should rebase on dev, not release https://github.com/tinygo-org/bluetooth/blob/release/CONTRIBUTING.md

Done! Actually, dev and release are both up to date at that time

@gen2thomas
Copy link

Checking by another way than changing or writing is normally a bad practice. One reason against this is that there is a low probability that the verification will be OK, but the conditions may have changed by the time the actual call begins.

In best case the called method returns an error of type "BufferFull" or whatever causing the problem and the caller can react on that, e.g. by wait and retry.

Unfortunately in our case the called method "cbgo.Pheripheral.WriteCharacteristic" has no error. So, IMO, we should fix that problem at a higher level (with your PR). I assume that is what your proposal already means:

(maybe the WriteWithoutResponse command should call CanSendWriteWithoutResponse instead and fail if it returns false ?)

@acouvreur
Copy link
Author

Checking by another way than changing or writing is normally a bad practice. One reason against this is that there is a low probability that the verification will be OK, but the conditions may have changed by the time the actual call begins.

In best case the called method returns an error of type "BufferFull" or whatever causing the problem and the caller can react on that, e.g. by wait and retry.

Unfortunately in our case the called method "cbgo.Pheripheral.WriteCharacteristic" has no error. So, IMO, we should fix that problem at a higher level (with your PR). I assume that is what your proposal already means:

(maybe the WriteWithoutResponse command should call CanSendWriteWithoutResponse instead and fail if it returns false ?)

That makes perfect sense, however CoreBluetooth itself is being used that way.

I'm not sure if it is possible to guarantee atomicity up to the driver level.

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

Successfully merging this pull request may close these issues.

3 participants