Пример #1
0
	def write(self, value, withResponse=False):
		"""Blocking write of the descriptor.

		Args:
			value : a bytearray of length at most send MTU - 3
		Raises:
			ClientError on failure
		"""

		assert isinstance(value, bytearray)

		op = att.OP_WRITE_REQ if withResponse else att.OP_WRITE_CMD
		req = bytearray([op])
		req += _handle_to_bytearray(self._handleNo)
		req += value

		if not withResponse:
			self.client._socket._send(req)
			return

		resp = self.client._new_transaction(req)
		if resp is None:
			raise ClientError("no response")
		elif resp[0] == att.OP_WRITE_RESP:
			return resp[1:]
		elif resp[0] == att.OP_ERROR and len(resp) == att_pdu.ERROR_PDU_LEN:
			raise ClientError("write failed - %s" % att.ecodeLookup(resp[4]))
		else:
			raise ClientError("unexpected - %s" % att.opcodeLookup(resp[0]))
Пример #2
0
	def read(self):
		"""Blocking read of the descriptor.

		Returns:
			A bytearray
		Raises:
			ClientError on failure
		"""

		if self._cachable and self._cached is not None:
			return self._cached

		req = bytearray([att.OP_READ_REQ])
		req += _handle_to_bytearray(self._handleNo)
		resp = self.client._new_transaction(req)
		if resp is None:
			raise ClientError("no response")
		elif resp[0] == att.OP_READ_RESP:
			ret = resp[1:]
			if self._cachable:
				self._cached = ret
			return ret
		elif resp[0] == att.OP_ERROR and len(resp) == att_pdu.ERROR_PDU_LEN:
			raise ClientError("read failed - %s" % att.ecodeLookup(resp[4]))
		else:
			raise ClientError("unexpected - %s" % att.opcodeLookup(resp[0]))
Пример #3
0
	def write(self, value, withResponse=True):
		"""Blocking write of the characteristic.

		Args:
			value : a bytearray of length at most send MTU - 3
			withResponse : whether the write should be a request or command
		Raises:
			ClientError on failure
		"""
		assert isinstance(value, bytearray)
		if "w" not in self.permissions:
			raise ClientError("write not permitted")

		op = att.OP_WRITE_REQ if withResponse else att.OP_WRITE_CMD
		req = bytearray([op])
		req += _handle_to_bytearray(self._valHandleNo)
		req += value

		if not withResponse:
			self.client._socket._send(req)
			return

		resp = self.client._new_transaction(req)
		if resp is None:
			raise ClientError("no response")
		elif resp[0] == att.OP_WRITE_RESP:
			return resp[1:]
		elif resp[0] == att.OP_ERROR and len(resp) == att_pdu.ERROR_PDU_LEN:
			raise ClientError("write failed - %s" % att.ecodeLookup(resp[4]))
		else:
			raise ClientError("unexpected - %s" % att.opcodeLookup(resp[0]))
Пример #4
0
	def __discover_services_by_uuid(self, uuid, startHandle, endHandle):
		primSvcUuid = UUID(gatt.PRIM_SVC_UUID)

		services = []
		newServices = []
		serviceHandles = {}
		currHandle = startHandle

		while True:
			req = att_pdu.new_find_by_type_value_req(currHandle, endHandle,
				primSvcUuid, uuid.raw[::-1])

			resp = self._new_transaction(req)
			if not resp:
				raise ClientError("transaction failed")

			if resp[0] == att.OP_FIND_BY_TYPE_REQ:
				idx = 2

				endGroup = currHandle # not needed
				while idx < len(resp) and idx + 4 <= len(resp):
					handleNo = att_pdu.unpack_handle(resp, idx)
					endGroup = att_pdu.unpack_handle(resp, idx + 2)

					if handleNo in self._serviceHandles:
						service = self._serviceHandles[handleNo]
					else:
						service = _ClientService(self, uuid, handleNo, endGroup)
						serviceHandles[handleNo] = service
						newServices.append(service)
					services.append(service)

					idx += 4

				currHandle = endGroup + 1
				if currHandle >= endHandle:
					break

			elif (resp[0] == att.OP_ERROR and len(resp) == att_pdu.ERROR_PDU_LEN
				and resp[1] == att.OP_FIND_BY_TYPE_REQ
				and resp[4] == att.ECODE_ATTR_NOT_FOUND):
				break

			elif (resp[0] == att.OP_ERROR and len(resp) == att_pdu.ERROR_PDU_LEN
				and resp[1] == att.OP_FIND_BY_TYPE_REQ):
				raise ClientError("error - %s" % att.ecodeLookup(resp[4]))

			else:
				raise ClientError("unexpected - %s" % att.opcodeLookup(resp[0]))

		self.services.extend(newServices)
		self.services.sort(key=lambda x: x._handleNo)
		self._serviceHandles.update(serviceHandles)

		return services
Пример #5
0
	def __discover_services(self, startHandle, endHandle):
		primSvcUuid = UUID(gatt.PRIM_SVC_UUID)

		services = []
		serviceHandles = {}
		currHandle = startHandle
		while True:
			req = att_pdu.new_read_by_group_req(currHandle, endHandle,
				primSvcUuid)

			resp = self._new_transaction(req)
			if not resp:
				raise ClientError("transaction failed")

			if resp[0] == att.OP_READ_BY_GROUP_RESP:
				attDataLen = resp[1]
				idx = 2

				endGroup = currHandle # not needed
				while idx < len(resp) and idx + attDataLen <= len(resp):
					handleNo = att_pdu.unpack_handle(resp, idx)
					endGroup = att_pdu.unpack_handle(resp, idx + 2)
					uuid = UUID(resp[idx+4:idx+attDataLen], reverse=True)

					service = _ClientService(self, uuid, handleNo, endGroup)
					services.append(service)
					serviceHandles[handleNo] = service

					idx += attDataLen

				currHandle = endGroup + 1
				if currHandle >= endHandle:
					break

			elif (resp[0] == att.OP_ERROR and len(resp) == att_pdu.ERROR_PDU_LEN
				and resp[1] == att.OP_READ_BY_GROUP_REQ
				and resp[4] == att.ECODE_ATTR_NOT_FOUND):
				break

			elif (resp[0] == att.OP_ERROR and len(resp) == att_pdu.ERROR_PDU_LEN
				and resp[1] == att.OP_READ_BY_GROUP_REQ):
				raise ClientError("error - %s" % att.ecodeLookup(resp[4]))

			else:
				raise ClientError("unexpected - %s" % att.opcodeLookup(resp[0]))

		return services, serviceHandles
Пример #6
0
	def read(self):
		"""Blocking read of the characteristic.

		Returns:
			A bytearray
		Raises:
			ClientError on failure
		"""
		if "r" not in self.permissions:
			raise ClientError("read not permitted")

		req = bytearray([att.OP_READ_REQ])
		req += _handle_to_bytearray(self._valHandleNo)
		resp = self.client._new_transaction(req)
		if resp is None:
			raise ClientError("no response")
		elif resp[0] == att.OP_READ_RESP:
			return resp[1:]
		elif resp[0] == att.OP_ERROR and len(resp) == att_pdu.ERROR_PDU_LEN:
			raise ClientError("read failed - %s" % att.ecodeLookup(resp[4]))
		else:
			raise ClientError("unexpected - %s" % att.opcodeLookup(resp[0]))
Пример #7
0
	def __discover_all_characteristics(self):
		startHandle = self._handleNo + 1
		endHandle = self._endGroup
		if startHandle > endHandle:
			return [], {}

		characUuid = UUID(gatt.CHARAC_UUID)

		characs = []
		characHandles = {}
		currHandle = startHandle
		while True:
			req = att_pdu.new_read_by_type_req(currHandle, endHandle,
				characUuid)

			resp = self.client._new_transaction(req)
			if not resp:
				raise ClientError("transaction failed")

			if resp[0] == att.OP_READ_BY_TYPE_RESP:
				attDataLen = resp[1]
				idx = 2

				maxHandleNo = currHandle # not needed
				while idx < len(resp) and idx + attDataLen <= len(resp):
					handleNo = att_pdu.unpack_handle(resp, idx)
					properties = resp[idx+2]
					valHandleNo = att_pdu.unpack_handle(resp, idx + 3)
					uuid = UUID(resp[idx+5:idx+attDataLen], reverse=True)

					charac = _ClientCharacteristic(self.client, self, uuid,
						handleNo, properties, valHandleNo)
					characs.append(charac)
					characHandles[handleNo] = characs

					idx += attDataLen
					maxHandleNo = valHandleNo

				currHandle = maxHandleNo + 1
				if currHandle >= endHandle:
					break

			elif (resp[0] == att.OP_ERROR and len(resp) == att_pdu.ERROR_PDU_LEN
				and resp[1] == att.OP_READ_BY_TYPE_REQ
				and resp[4] == att.ECODE_ATTR_NOT_FOUND):
				break

			elif (resp[0] == att.OP_ERROR and len(resp) == att_pdu.ERROR_PDU_LEN
				and resp[1] == att.OP_READ_BY_TYPE_REQ
				and resp[4] == att.ECODE_READ_NOT_PERM):
				currHandle = currHandle + 1
				if currHandle >= endHandle:
					break

			elif (resp[0] == att.OP_ERROR and len(resp) == att_pdu.ERROR_PDU_LEN
				and resp[1] == att.OP_READ_BY_TYPE_REQ):
				raise ClientError("error - %s" % att.ecodeLookup(resp[4]))

			else:
				raise ClientError("unexpected - %s" % att.opcodeLookup(resp[0]))

		for i, charac in enumerate(characs):
			if i + 1 < len(characs):
				charac._set_end_group(characs[i+1]._handleNo-1)
			else:
				charac._set_end_group(self._endGroup)

		return characs, characHandles
Пример #8
0
	def discoverDescriptors(self):
		"""Return a list of descriptors"""

		assert self._endGroup is not None

		startHandle = self._handleNo + 1
		endHandle = self._endGroup
		if startHandle > endHandle:
			return []

		descriptors = []

		cccdUuid = UUID(gatt.CLIENT_CHARAC_CFG_UUID)
		cccd = None

		userDescUuid = UUID(gatt.CHARAC_USER_DESC_UUID)
		userDesc = None

		currHandle = startHandle
		while True:
			req = att_pdu.new_find_info_req(currHandle, endHandle)

			resp = self.client._new_transaction(req)
			if not resp:
				raise ClientError("transaction failed")

			if resp[0] == att.OP_FIND_INFO_RESP:
				attDataLen = 4 if resp[1] == att.FIND_INFO_RESP_FMT_16BIT \
					else 18
				idx = 2

				handleNo = currHandle # not needed
				while idx < len(resp) and idx + attDataLen <= len(resp):
					handleNo = att_pdu.unpack_handle(resp, idx)
					uuid = UUID(resp[idx+2:idx+attDataLen], reverse=True)

					if handleNo == self._valHandleNo:
						idx += attDataLen
						continue

					if uuid == userDescUuid:
						descriptor = _ClientDescriptor(self.client, self, uuid,
							handleNo, cacheable=True)
						userDesc = descriptor
					else:
						descriptor = _ClientDescriptor(self.client, self, uuid,
							handleNo)

					if uuid == cccdUuid:
						# hide the cccd from users
						cccd = descriptor
					else:
						descriptors.append(descriptor)

					idx += attDataLen

				currHandle = handleNo + 1
				if currHandle >= endHandle:
					break

			elif (resp[0] == att.OP_ERROR and len(resp) == att_pdu.ERROR_PDU_LEN
				and resp[1] == att.OP_FIND_INFO_REQ
				and resp[4] == att.ECODE_ATTR_NOT_FOUND):
				break

			elif (resp[0] == att.OP_ERROR and len(resp) == att_pdu.ERROR_PDU_LEN
				and resp[1] == att.OP_FIND_INFO_REQ):
				raise ClientError("error - %s" % att.ecodeLookup(resp[4]))

			else:
				raise ClientError("unexpected - %s" % att.opcodeLookup(resp[0]))

		self.descriptors = descriptors
		self._cccd = cccd
		self._user_desc = userDesc
		return descriptors