bluetooth.py 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911
  1. import _bluetooth
  2. # 特性标志位
  3. FLAG_BROADCAST = 0x0001
  4. FLAG_READ = 0x0002
  5. FLAG_WRITE_NO_RESPONSE = 0x0004
  6. FLAG_WRITE = 0x0008
  7. FLAG_NOTIFY = 0x0010
  8. FLAG_INDICATE = 0x0020
  9. FLAG_AUTHENTICATED_SIGNED_WRITE = 0x0040
  10. # 描述符标志位
  11. FLAG_DSC_READ = 0x01
  12. FLAG_DSC_WRITE = 0x02
  13. FLAG_DSC_READ_ENC = 0x04
  14. FLAG_DSC_READ_AUTHEN = 0x08
  15. FLAG_DSC_READ_AUTHOR = 0x10
  16. FLAG_DSC_WRITE_ENC = 0x20
  17. FLAG_DSC_WRITE_AUTHEN = 0x40
  18. FLAG_DSC_WRITE_AUTHOR = 0x80
  19. FLAG_AUX_WRITE = 0x0100
  20. FLAG_READ_ENCRYPTED = 0x0200
  21. FLAG_READ_AUTHENTICATED = 0x0400
  22. FLAG_READ_AUTHORIZED = 0x0800
  23. FLAG_WRITE_ENCRYPTED = 0x1000
  24. FLAG_WRITE_AUTHENTICATED = 0x2000
  25. FLAG_WRITE_AUTHORIZED = 0x4000
  26. '''
  27. 创建具有指定值的 UUID 实例
  28. 该值可以是
  29. - 一个 16 位整数. 例如`0x2908`
  30. - 一个 32 位整数. 例如`0x29081234`
  31. - 一个 128 位的 UUID 字符串。例如`'6E400001-B5A3-F393-E0A9-E50E24DCCA9E'`.
  32. '''
  33. class UUID():
  34. def __init__(self,value):
  35. # try:
  36. self.value,self._UUID_bits = self._UUID_to_bytes(value)
  37. # except:
  38. # print("ValueError: Invalid UUID")
  39. # raise ValueError
  40. def _UUID_to_bytes(self,value):
  41. value_bytes = []
  42. UUID_bits = 0
  43. # try:
  44. if isinstance(value,bytearray):
  45. value_bytes = bytes(value.decode()) # 暂不支持bytes(bytearray())
  46. if len(value_bytes) > 16 :
  47. value_bytes = []
  48. # raise ValueError
  49. raise ValueError
  50. elif isinstance(value, bytes):
  51. value_bytes = value
  52. elif isinstance(value,str):
  53. # if len(value) == 36 and (value[8] == value[13] == value[18] == value[23] == '-'): #暂不支持连等
  54. if len(value) == 36 and (value[8] == '-') and (value[13] == '-') and (value[18] == '-') and (value[23] == '-'):
  55. value_str = value.replace("-","")
  56. value_list = []
  57. if len(value_str) == 32:
  58. for i in range(0, 32, 2):
  59. value_list.append(int(value_str[i:i+2],16))
  60. value_bytes = bytes(value_list)
  61. else :
  62. raise ValueError
  63. else :
  64. raise ValueError
  65. elif isinstance(value,int):
  66. value_list = []
  67. if value >= 0 and value < 65536 : #16 bit uuid
  68. value_list.append(int(value/256))
  69. value_list.append(value%256)
  70. elif value >= 0 and value < 65536 * 65536: #32 bit uuid
  71. value_list.append(int(value/(65536 * 256)))
  72. value_list.append(int((value%(65536 * 256))/65536))
  73. value_list.append(int((value%(65536))/256))
  74. value_list.append((value%(256)))
  75. else :
  76. raise ValueError
  77. value_bytes = bytes(value_list)
  78. else:
  79. raise ValueError
  80. UUID_bits = len(value_bytes) # bytes的数量
  81. return value_bytes,UUID_bits
  82. class BLE(_bluetooth.BLE):
  83. def __init__(self):
  84. print("BLE init")
  85. # a = super().__init__()
  86. self._last_adv_data = "" #广播内容
  87. self._last_resp_data = "" #回应扫描内容
  88. self._addr_mode = 0 #地址类型 BLE_OWN_ADDR_PUBLIC,BLE_OWN_ADDR_RANDOM,BLE_OWN_ADDR_RPA_PUBLIC_DEFAULT,BLE_OWN_ADDR_RPA_RANDOM_DEFAULT
  89. self._callback_func = None #回调函数
  90. self._basic_value_handle = 20
  91. self._connectable = True
  92. self._py2c_dict = {}
  93. self._c2py_dict = {}
  94. self._c2value_dict = {}
  95. self._append_adv_data = True
  96. a = self.init()
  97. self.setCallback(self._callback)
  98. # 测试函数
  99. def test(self):
  100. if self.pyi_check_active() == False:
  101. raise OSError
  102. def test2(self):
  103. self.test()
  104. # return self.pyi_test2()s
  105. def test3(self,connhandle,valuehandle):
  106. return self.pyi_test3(connhandle,valuehandle)
  107. def test4(self,data):
  108. pass
  109. def test_call_some_name(self):
  110. super().test_call_some_name()
  111. # 检查蓝牙活跃性
  112. def _check_active(self):
  113. if self.pyi_check_active() == False:
  114. raise OSError
  115. '''
  116. 可选择更改 BLE 无线电的活动状态,并返回当前状态。
  117. Args:
  118. - active(bool): 为 1 则开启BLE, 否则关闭BLE; 为空则查询当前BLE状态
  119. Returns:
  120. - bool:设置状态时,返回操作成功与否; 查询状态时, 返回状态, True为活跃
  121. '''
  122. def active(self,active_flag = None ):
  123. if active_flag == None:
  124. return self.pyi_check_active()
  125. else:
  126. if (active_flag > 0 or active_flag == True):
  127. return self.pyi_active(True)
  128. elif (active_flag == 0 or active_flag == False):
  129. return self.pyi_active(False)
  130. '''
  131. 获取或设置 BLE 接口的配置值。
  132. 要获得一个值,参数名称应该被引用为一个字符串,并且一次只查询一个参数。
  133. 如 `config("gap_name")`
  134. 要设置值,请使用关键字语法,并且一次可以设置一个或多个参数。
  135. 如 `config(gap_name="nimble")`
  136. 当前支持的值是:
  137. - `'mac'`:
  138. TODO:需要支持设置任意值嘛?有点困难
  139. - `'addr_mode'`:
  140. - `'gap_name'`:
  141. - `'rxbuf'`:
  142. TODO:暂未支持, 没找到对应函数
  143. - `'mtu'`:
  144. TODO:不明意义
  145. - `'bond'`:
  146. TODO: 目前提供的接口不支持
  147. - `'mitm'`:
  148. TODO: 目前提供的接口不支持
  149. - `'io'`:
  150. TODO:未找到对应函数
  151. - `'lesure'`:
  152. TODO:只支持设置
  153. '''
  154. def config(self, *param_name, **kv): # a.config(mac="1123",gap_name="test")
  155. # 获取参数属性 a.config("mac")
  156. try:
  157. self._check_active()
  158. except:
  159. raise OSError
  160. if len(param_name) != 0 :
  161. first_param = param_name[0]
  162. if first_param == "mac":
  163. return (self.config_addr_mode_get(),self.config_mac_get())
  164. elif first_param == "addr_mode":
  165. return self.config_addr_mode_get()
  166. elif first_param == "gap_name":
  167. return self.config_gap_name_get()
  168. # elif first_param == "rxbuf" :
  169. # self.config_addr_rxbuf_get()
  170. # elif first_param == "mtu" :
  171. # self.config_mtu_get()
  172. # elif first_param == "bond" :
  173. # self.config_bond_get()
  174. # elif first_param == "mitm" :
  175. # self.config_mitm_get()
  176. # elif first_param == "io":
  177. # self.config_io_get()
  178. # elif first_param == "le_secure":
  179. # self.config_le_secure_get()
  180. elif first_param == "gap_uuid":
  181. return self.config_gap_uuid_get()
  182. else:
  183. print("ValueError: unknown config param")
  184. # 设置参数
  185. if "mac" in kv:
  186. self.config_mac_update(kv["mac"])
  187. if ("addr_mode" in kv):
  188. self.config_addr_mode_update(kv["_addr_mode"])
  189. if ("gap_name" in kv):
  190. self.config_gap_name_update(kv["gap_name"])
  191. # if ("rxbuf" in kv):
  192. # return self.config_rxbuf_update(kv["rxbuf"])
  193. # if ("mtu" in kv):
  194. # return self.config_mtu_update(kv["mtu"])
  195. # if ("bond" in kv):
  196. # return self.config_bond_update(kv["bond"])
  197. # if ("mitm" in kv):
  198. # return self.config_mitm_update(kv["mitm"])
  199. # if ("bond" in kv):
  200. # return self.config_mac_update(kv["bond"])
  201. # if ("io" in kv):
  202. # return self.config_io_update(kv["io"])
  203. # if ("le_secire" in kv):
  204. # return self.config_le_secire_update(kv["le_secire"])
  205. if ("gap_uuid" in kv):
  206. uuid = kv["gap_uuid"]
  207. if isinstance(uuid,UUID):
  208. self.config_gap_uuid_update(uuid.value,uuid._UUID_bits)
  209. '''
  210. 为来自 BLE 堆栈的事件注册回调。
  211. 处理程序采用两个参数,event(在下面的代码中的一个) 和 data(其是值的特定事件元组)。
  212. '''
  213. # 回调事件处理函数
  214. def irq(self,func):
  215. self._callback_func = func
  216. return 0
  217. def _callback(self,data):
  218. event_id = data[0]
  219. # print("_callback call")
  220. # print("event_id",event_id)
  221. # print("data ",data[1])
  222. if self._callback_func != None:
  223. if event_id > 100 : #自定义回调事件
  224. if event_id == 101 : # 建立句柄映射
  225. ble_value_handles = data[1]
  226. length = len(ble_value_handles)
  227. for i in range(length):
  228. key = self._basic_value_handle + i
  229. value = ble_value_handles[i]
  230. # py 映射 c handle
  231. self._py2c_dict[str(key)] = value
  232. # c 映射 py handle
  233. self._c2py_dict[str(value)] = key
  234. # c handle 映射 value, 默认值为空
  235. self._c2value_dict[str(value)] = bytes("")
  236. elif event_id == 102: #nimble蓝牙协议栈读属性
  237. buf = self._c2value_dict[str(data[1])]
  238. return len(buf),buf
  239. else:
  240. if event_id == 3: # write
  241. self._c2_change_value(data[2], data[3])
  242. data = data[:3]
  243. elif event_id == 4: # read 请求
  244. rc = self._callback_func(event_id,data[1:])
  245. value = -99
  246. length = -99
  247. if rc == 0: #允许读
  248. value = self._c2value(data[2])
  249. length = len(value)
  250. return rc,length,value
  251. else:
  252. return self._callback_func(event_id,data[1:])
  253. '''
  254. 以指定的时间间隔(以微秒为单位)开始广播。
  255. adv_data和resp_data可以是任何实现缓冲协议的类型(例如bytes, bytearray, str)。adv_data包含在所有广播中,并且resp_data被发送以响应主动扫描。
  256. 注意:如果adv_data(或resp_data)是None, 则传递给前一个调用的数据 gap_advertise将被重新使用。
  257. 要清除广告有效负载, 请传递一个空值bytes, 即b''
  258. Args:
  259. - interval_us(int):广播时间间隔, 单位us. 此间隔将向下舍入到最接近的 625us的倍数。要停止广告, 请将interval_us设置 为 None。
  260. - adv_data(bytes, bytearray, str): 自定义广播数据(添加到默认广播数据后),默认值为none
  261. TODO:1.append模式只能是0XFF数据; 归零模式全部自定义输入
  262. - resp_data(bytes, bytearray, str): 扫描响应数据,默认值为none
  263. - connectable(bool): 是否可连接, True 为可连接.
  264. - adv_data_append: 是否是增加数据
  265. TODO:存在问题
  266. '''
  267. def gap_advertise(self, interval_us,adv_data=None,resp_data=None, connectable=None, adv_data_append=None):
  268. try:
  269. self._check_active()
  270. except:
  271. raise OSError
  272. if connectable != None:
  273. self._connectable = connectable
  274. if interval_us is None:
  275. return self.stop_advertise()
  276. else:
  277. # 设置广播载荷
  278. if adv_data is None: #参数为空,则使用上次数据广播数据
  279. adv_data = self._last_adv_data
  280. else :
  281. if adv_data_append != None: # 设置是否增加数据
  282. self._append_adv_data = adv_data_append
  283. if self._append_adv_data == True: # 新增数据
  284. self._last_adv_data = _to_bytes(adv_data)
  285. else: # 覆盖数据
  286. empty_list = []
  287. for i in range(len(adv_data)):
  288. empty_list.append(len(adv_data[i]))
  289. empty_list += adv_data[i]
  290. # print(empty_list)
  291. self._last_adv_data = _to_bytes(empty_list)
  292. # 设置响应载荷
  293. if resp_data is None:
  294. resp_data = self._last_resp_data
  295. else :
  296. self._last_resp_data = _to_bytes(resp_data)
  297. # self._adv_data_append = False
  298. # print("_addr_mode : ",self._addr_mode)
  299. # print("int(interval_us/625) : ",int(interval_us/625))
  300. # print("self._connectable: ",self._connectable)
  301. # print("self._last_adv_data : ",self._last_adv_data)
  302. # print("len(self._last_adv_data) : ",len(self._last_adv_data))
  303. # print("adv_data_append : ",self._append_adv_data)
  304. # print("self._b",self._b)
  305. # print("self._last_resp_data : ",self._last_resp_data)
  306. # print("len(self._last_resp_data) : ",len(self._last_resp_data))
  307. return self.advertise(self._addr_mode,int(interval_us/625),self._connectable,self._last_adv_data,
  308. len(self._last_adv_data),self._append_adv_data,self._last_resp_data,len(self._last_resp_data))
  309. '''
  310. 运行持续指定持续时间(以毫秒为单位)的扫描操作。
  311. 要无限期扫描, 请将duration_ms设置为0;要停止扫描,请将duration_ms设置为 None.
  312. 使用interval_us和window_us可选择配置占空比。扫描器将每interval_us微秒运行window_us 微秒,总共持续duration_ms毫秒。
  313. 默认间隔和窗口分别为 1.28 秒和 11.25 毫秒(后台扫描).
  314. 对于每个扫描结果, _IRQ_SCAN_RESULT将引发事件, 并带有事件数据。`(addr_type, addr, adv_type, rssi, adv_data)`
  315. Args:
  316. - duration_ms(int):扫描持续时间。要无限期扫描, 请将duration_ms设置为0;要停止扫描,请将duration_ms设置为 None.
  317. - interval_us(int): 扫描间间隔时间。默认值为1280000
  318. - window_us(int): 扫描窗口时间。默认值为11250
  319. - active(bool): 是否接受扫描响应。默认值False(不接受)
  320. Return:
  321. - 操作成功返回 0; 否则返回错误代码
  322. events:
  323. - 单个扫描结果触发 _IRQ_SCAN_RESULT
  324. - 扫描结束触发 _IRQ_SCAN_DONE
  325. '''
  326. def gap_scan(self, duration_ms, interval_us=1280000, window_us=11250, active=False):
  327. try:
  328. self._check_active()
  329. except:
  330. raise OSError
  331. self._check_active()
  332. if duration_ms is None :
  333. return self.gap_stop_disc()
  334. else:
  335. return self.gap_disc(self._addr_mode, duration_ms,int(interval_us/625),int(window_us/625),active)
  336. '''
  337. central 设备连接 peripherals 设备
  338. Args:
  339. - peer_addr(list,bytes,bytearray): 需要连接的设备的mac地址
  340. - peer_addr_type(int): 连接设备的地址类型
  341. - 0x00 - PUBLIC - 使用控制器的公共地址。
  342. - 0x01 - RANDOM - 使用生成的静态地址。
  343. - 0x02 - RPA - 使用可解析的私有地址。
  344. - 0x03 - NRPA - 使用不可解析的私有地址。
  345. Return:
  346. - (int): 操作成功返回 0; 否则返回错误代码
  347. events:
  348. - 连接成功触发 CENTRAL设备:_IRQ_PERIPHERAL_CONNECT; PERIPHERAL设备:_IRQ_CENTRAL_CONNECT
  349. '''
  350. def gap_connect(self,peer_addr,peer_addr_type, scan_duration_ms=2000):
  351. try:
  352. self._check_active()
  353. except:
  354. raise OSError
  355. self._check_active()
  356. peer_addr_bytes = _to_bytes(peer_addr,6)
  357. return self.pyi_gap_connect(peer_addr_bytes,peer_addr_type ,scan_duration_ms)
  358. '''
  359. Args:
  360. - conn_handle(int): 连接句柄
  361. Return:
  362. - (int): 操作成功返回 0; 否则返回错误代码
  363. events:
  364. - 断连成功触发 CENTRAL设备:_IRQ_PERIPHERAL_DISCONNECT; PERIPHERAL设备:_IRQ_CENTRAL_DISCONNECT
  365. '''
  366. def gap_disconnect(self, conn_handle):
  367. try:
  368. self._check_active()
  369. except:
  370. raise OSError
  371. self._check_active()
  372. return self.pyi_gap_disconnect(conn_handle)
  373. '''
  374. 使用指定的服务配置服务器,替换任何现有服务。
  375. Args:
  376. - services(嵌套多层tuple):
  377. Return:
  378. - (int): 操作成功返回 0; 否则返回错误代码
  379. '''
  380. def gatts_register_services(self, services):
  381. try:
  382. self._check_active()
  383. except:
  384. raise OSError
  385. self._check_active()
  386. convert_services = _convert_ble_service_info(services)
  387. offset = 0
  388. chr_list = _count_chrs(services) #计算每个服务的特性数量
  389. all_chr_count = 0
  390. py_handles = []
  391. # 计算py handle返回值
  392. # 计算chr总数量
  393. for i in range(len(chr_list)):
  394. py_handles_one_service = []
  395. all_chr_count += chr_list[i]
  396. for j in range(chr_list[i]):
  397. value_handle = self._basic_value_handle + offset
  398. py_handles_one_service.append(value_handle)
  399. offset += 1
  400. py_handles.append(py_handles_one_service)
  401. rc = self.gatts_register_svcs(convert_services,all_chr_count)
  402. if rc != 0 :
  403. return rc
  404. return tuple(py_handles)
  405. '''
  406. Args:
  407. - value_handle(int): 蓝牙特性句柄
  408. Return:
  409. - (int): 操作成功返回 0; 否则返回错误代码
  410. '''
  411. def gatts_read(self,value_handle):
  412. try:
  413. self._check_active()
  414. except:
  415. raise OSError
  416. return self._py2value(value_handle)
  417. '''
  418. Args:
  419. - value_handle(int): 蓝牙特性句柄
  420. - data(str,int,bytes,list(元素为小于256大于0的整数)): 修改的数据
  421. - send_update(bool):是否通知客户端, False为不通知, 默认为False
  422. Return:
  423. - (int): 操作成功返回 0; 否则返回错误代码
  424. events:
  425. - send_update 为 True 时, 触发tx事件
  426. '''
  427. def gatts_write(self,value_handle, data, send_update=False):
  428. try:
  429. self._check_active()
  430. except:
  431. raise OSError
  432. print("send_update=", send_update)
  433. if send_update == False:
  434. return self._py2_change_value(value_handle,data)
  435. else :
  436. rc = self._py2_change_value(value_handle,data)
  437. if rc != 0:
  438. return rc
  439. return self.gatts_chr_updated(self._py2c_dict[str(value_handle)])
  440. '''
  441. 向连接的客户端发送通知请求。
  442. Args:
  443. - conn_handle(int): 连接句柄
  444. - value_handle(int): 蓝牙特性句柄
  445. - data(str,int,bytes,list(元素为小于256大于0的整数)): 发送的数据, 默认值为None
  446. 如果data不是None, 则该值将作为通知的一部分发送给客户端。本地值不会被修改。否则, 如果data是None, 则将发送当前本地值
  447. Return:
  448. - (int): 操作成功返回 0; 否则返回错误代码
  449. events:
  450. -
  451. '''
  452. def gatts_notify(self,conn_handle, value_handle, data=None):
  453. try:
  454. self._check_active()
  455. except:
  456. raise OSError
  457. self._check_active()
  458. value = ""
  459. if data is None:
  460. value = self._py2value(value_handle)
  461. c_value_handle = self._py2c_dict[str(value_handle)]
  462. else :
  463. if isinstance(data,bytes): #TODO:关注一下数据类型
  464. value = data
  465. elif isinstance(data,int):
  466. value = bytes([data])
  467. else:
  468. value = bytes(data)
  469. c_value_handle = self._py2c_dict[str(value_handle)]
  470. self.pyi_gatts_notify(conn_handle, c_value_handle,value,len(value))
  471. '''
  472. Args:
  473. -
  474. Return:
  475. - 操作是否成功
  476. events:
  477. -
  478. '''
  479. def gatts_indicate(self,conn_handle, value_handle,data=None):
  480. try:
  481. self._check_active()
  482. except:
  483. raise OSError
  484. value = ""
  485. if data is None:
  486. value = self._py2value(value_handle)
  487. c_value_handle = self._py2c_dict[str(value_handle)]
  488. else :
  489. if isinstance(data,bytes):
  490. value = data
  491. elif isinstance(data,int):
  492. value = bytes([data])
  493. else:
  494. value = bytes(data)
  495. c_value_handle = self._py2c_dict[str(value_handle)]
  496. self.pyi_gatts_indicate(conn_handle, c_value_handle,value,len(value))
  497. '''
  498. Args:
  499. -
  500. Return:
  501. - 操作是否成功
  502. events:
  503. -
  504. '''
  505. def gatts_set_buffer(self,value_handle, len, append=False):
  506. try:
  507. self._check_active()
  508. except:
  509. raise OSError
  510. # TODO:暂不清楚对照哪个函数
  511. pass
  512. '''
  513. 打印全部本地服务
  514. '''
  515. def gatts_show_local(self):
  516. try:
  517. self._check_active()
  518. except:
  519. raise OSError
  520. return self.pyi_gatts_show_local()
  521. '''
  522. Args:
  523. -
  524. Return:
  525. - 操作是否成功
  526. events:
  527. -
  528. '''
  529. def gattc_discover_services(self,conn_handle, uuid:UUID=None):
  530. try:
  531. self._check_active()
  532. except:
  533. raise OSError
  534. if uuid == None:
  535. return self.gattc_dis_svcs(conn_handle)
  536. else :
  537. return self.gattc_dis_svcs_by_uuid(conn_handle,uuid.value,len(uuid.value))
  538. '''
  539. Args:
  540. -
  541. Return:
  542. - 操作是否成功
  543. events:
  544. -
  545. '''
  546. def gattc_discover_characteristics(self,conn_handle, start_handle, end_handle, uuid:UUID=None):
  547. try:
  548. self._check_active()
  549. except:
  550. raise OSError
  551. if uuid == None:
  552. return self.gattc_dis_chrs(conn_handle,start_handle,end_handle)
  553. else :
  554. return self.gattc_dis_chrs_by_uuid(conn_handle, start_handle, end_handle,uuid.value,len(uuid.value))
  555. '''
  556. Args:
  557. -
  558. Return:
  559. - 操作是否成功
  560. events:
  561. -
  562. '''
  563. def gattc_discover_descriptors(self,conn_handle, start_handle, end_handle):
  564. try:
  565. self._check_active()
  566. except:
  567. raise OSError
  568. return self.gattc_dis_dscs(conn_handle,start_handle, end_handle)
  569. '''
  570. Args:
  571. -
  572. Return:
  573. - 操作是否成功
  574. events:
  575. -
  576. '''
  577. def gattc_read(self,conn_handle, value_handle):
  578. try:
  579. self._check_active()
  580. except:
  581. raise OSError
  582. return self.pyi_gattc_read(conn_handle, value_handle)
  583. '''
  584. Args:
  585. -
  586. Return:
  587. - 操作是否成功
  588. 注意:单次传输最多95个byte
  589. events:
  590. -
  591. '''
  592. def gattc_write(self,conn_handle, value_handle, data, mode = 0):
  593. try:
  594. self._check_active()
  595. except:
  596. raise OSError
  597. if mode == 0:
  598. return self.gattc_write_with_no_rsp(conn_handle, value_handle, data, len(data))
  599. elif mode == 1:
  600. return self.gattc_write_with_rsp(conn_handle, value_handle, data,len(data))
  601. '''
  602. Args:
  603. -
  604. Return:
  605. - 操作是否成功
  606. events:
  607. -
  608. '''
  609. def gattc_exchange_mtu(self,conn_handle):
  610. try:
  611. self._check_active()
  612. except:
  613. raise OSError
  614. return self.pyi_gattc_exchange_mtu(conn_handle)
  615. def gattc_subscribe(self,conn_handle,value_handle,subscribe = 0):
  616. try:
  617. self._check_active()
  618. except:
  619. raise OSError
  620. return self.pyi_gattc_subscribe(conn_handle,value_handle,subscribe)
  621. # 通过C handle找值
  622. def _c2value(self, handle):
  623. return self._c2value_dict[str(handle)]
  624. # 通过PY handle找值
  625. def _py2value(self,handle):
  626. c_handlue = self._py2c_dict[str(handle)]
  627. return self._c2value(c_handlue)
  628. # return self._c2value(25)
  629. # 通过C handle 改值, value均为bytes类型
  630. def _c2_change_value(self,handle,value):
  631. value_bytes = 12
  632. # self._c2value_dict[str(handle)] = value_bytes
  633. self._c2value_dict[str(handle)] = value
  634. return 0
  635. # 通过py handle 改值
  636. def _py2_change_value(self,handle,value):
  637. if len(self._py2c_dict) == 0:
  638. return -1
  639. c_handlue = self._py2c_dict[str(handle)]
  640. value_bytes = _to_bytes(value)
  641. return self._c2_change_value(c_handlue,value_bytes)
  642. # 将UUID类型转换为字符串
  643. def _convert_ble_service_info(data):
  644. new_list = []
  645. for i in data :
  646. if isinstance(i,UUID) :
  647. new_list.append(i.value)
  648. new_list.append(i._UUID_bits)
  649. # print(i.value)
  650. elif isinstance(i, tuple):
  651. new_list.append(_convert_ble_service_info(i))
  652. else:
  653. new_list.append(i)
  654. # print(i)
  655. return tuple(new_list)
  656. def _count_chrs(srvs_tuple):
  657. srv_count = len(srvs_tuple)
  658. chr_count = [] # 每个服务的特性数量
  659. for i in range(srv_count):
  660. if len(srvs_tuple[i]) > 1 :
  661. chr_count.append(len(srvs_tuple[i][1]))
  662. else :
  663. chr_count.append(0)
  664. return chr_count
  665. def _to_bytes(data,size=None):
  666. data_bytes = []
  667. if isinstance(data,bytes):
  668. data_bytes = data
  669. elif isinstance(data,bytearray):
  670. data_bytes = bytes(data.decode())
  671. elif isinstance(data,str):
  672. data_bytes = bytes(data)
  673. elif isinstance(data,list):
  674. data_bytes = bytes(data)
  675. elif isinstance(data,int):
  676. data_list = []
  677. if data == 0:
  678. data_list.append(0)
  679. else :
  680. while data > 0:
  681. remainder = data % 256
  682. data_list.insert(0, remainder)
  683. data //= 256
  684. data_bytes = bytes(data_list)
  685. else:
  686. raise ValueError
  687. if size != None and len(data_bytes) != size:
  688. raise ValueError
  689. return data_bytes