blob: abac23fe3a8916404bffc7918156e4b11acff12f [file] [log] [blame]
Neeraj Poojary59f8b152019-02-01 14:15:57 -08001# Copyright 2019 The Chromium OS Authors. All rights reserved.
2# Use of this source code is governed by a BSD-style license that can be
3# found in the LICENSE file.
4
Archie Pusaka3c9fd0c2021-04-13 15:26:46 +08005"""This module provides an abstraction of the Nordic nRF52 BLE kit."""
Neeraj Poojary59f8b152019-02-01 14:15:57 -08006
7from __future__ import print_function
8
Archie Pusaka3c9fd0c2021-04-13 15:26:46 +08009# TODO: to port chromite.lib.cros_logging to replace legacy logging
10import logging # pylint: disable=cros-logging-import
Neeraj Poojary59f8b152019-02-01 14:15:57 -080011import time
12
Yu-Hsuan Hsu04cff0e2020-02-13 11:55:10 +080013from .bluetooth_peripheral_kit import PeripheralKit
14from .bluetooth_peripheral_kit import PeripheralKitException
Neeraj Poojary59f8b152019-02-01 14:15:57 -080015
16
17class nRF52Exception(PeripheralKitException):
18 """A dummy exception class for nRF52 class."""
Neeraj Poojary59f8b152019-02-01 14:15:57 -080019
20
21class nRF52(PeripheralKit):
Archie Pusaka3c9fd0c2021-04-13 15:26:46 +080022 """This is an abstraction of Nordic's nRF52 Dongle
23
24 It is used to emulate BLE mouse and keyboard functionality.
Neeraj Poojary59f8b152019-02-01 14:15:57 -080025
26 SDK: https://www.nordicsemi.com/Software-and-Tools/Software/nRF5-SDK
27
28 See autotest-private/nRF52/ble_app_hids/README for information about
29 using the SDK to compile the application.
30 """
31
32 # Serial port settings (override)
33 BAUDRATE = 115200
34 DRIVER = 'cdc_acm'
35 # Driver name in udev is 'cdc_acm', but builtin module is 'cdc-acm.ko'
36 # So we need to look for cdc_acm when searching by driver,
37 # but looking in builtins requires searching by 'cdc-acm'.
38 DRIVER_MODULE = 'cdc-acm'
39 BAUDRATE = 115200
Neeraj Poojary7a93d5a2019-07-01 13:56:10 -070040 USB_VID = '1366'
41 USB_PID = '1015'
Neeraj Poojary59f8b152019-02-01 14:15:57 -080042
43 # A newline can just be a '\n' to denote the end of a command
44 NEWLINE = '\n'
45 CMD_FS = ' ' # Command field separator
46
47 # Supported device types
48 MOUSE = 'MOUSE'
49 KEYBOARD = 'KEYBOARD'
Yoni Shavit75d7cf12019-03-27 13:35:05 -070050 KNOWN_DEVICE_SET = None
Neeraj Poojary59f8b152019-02-01 14:15:57 -080051
52 RESET_SLEEP_SECS = 1
53
54 # Mouse button constants
55 MOUSE_BUTTON_LEFT_BIT = 1
56 MOUSE_BUTTON_RIGHT_BIT = 2
57
58 # Specific Commands
59 # Reboot the nRF52
Archie Pusaka3c9fd0c2021-04-13 15:26:46 +080060 CMD_REBOOT = 'RBT'
Neeraj Poojary59f8b152019-02-01 14:15:57 -080061 # Reset the nRF52 and erase all previous bonds
Archie Pusaka3c9fd0c2021-04-13 15:26:46 +080062 CMD_FACTORY_RESET = 'FRST'
Neeraj Poojary59f8b152019-02-01 14:15:57 -080063 # Return the name that is sent in advertisement packets
Archie Pusaka3c9fd0c2021-04-13 15:26:46 +080064 CMD_GET_ADVERTISED_NAME = 'GN'
Neeraj Poojary59f8b152019-02-01 14:15:57 -080065 # Return the nRF52 firmware version
Archie Pusaka3c9fd0c2021-04-13 15:26:46 +080066 CMD_GET_FIRMWARE_VERSION = 'GV'
Neeraj Poojary59f8b152019-02-01 14:15:57 -080067 # Return the Bluetooth address of the nRF52
Archie Pusaka3c9fd0c2021-04-13 15:26:46 +080068 CMD_GET_NRF52_MAC = 'GM'
Neeraj Poojary59f8b152019-02-01 14:15:57 -080069 # Return the address of the device connected (if there exists a connection)
Archie Pusaka3c9fd0c2021-04-13 15:26:46 +080070 CMD_GET_REMOTE_CONNECTION_MAC = 'GC'
Neeraj Poojary59f8b152019-02-01 14:15:57 -080071 # Return the status of the nRF52's connection with a central device
Archie Pusaka3c9fd0c2021-04-13 15:26:46 +080072 CMD_GET_CONNECTION_STATUS = 'GS'
Neeraj Poojary59f8b152019-02-01 14:15:57 -080073
74 # Return the type of device the HID service is set
Archie Pusaka3c9fd0c2021-04-13 15:26:46 +080075 CMD_GET_DEVICE_TYPE = 'GD'
Neeraj Poojary59f8b152019-02-01 14:15:57 -080076 # Set the nRF52 HID service to mouse
Archie Pusaka3c9fd0c2021-04-13 15:26:46 +080077 CMD_SET_MOUSE = 'SM'
Neeraj Poojary59f8b152019-02-01 14:15:57 -080078 # Set the nRF52 HID service to keyboard
Archie Pusaka3c9fd0c2021-04-13 15:26:46 +080079 CMD_SET_KEYBOARD = 'SK'
Neeraj Poojary59f8b152019-02-01 14:15:57 -080080 # Start HID service emulation
Archie Pusaka3c9fd0c2021-04-13 15:26:46 +080081 CMD_START_HID_EM = 'START'
Neeraj Poojary59f8b152019-02-01 14:15:57 -080082 # Start HID service emulation
Archie Pusaka3c9fd0c2021-04-13 15:26:46 +080083 CMD_STOP_HID_EM = 'STOP'
Neeraj Poojary59f8b152019-02-01 14:15:57 -080084 # Start advertising with the current settings (HID type)
Archie Pusaka3c9fd0c2021-04-13 15:26:46 +080085 CMD_START_ADVERTISING = 'ADV'
Neeraj Poojary59f8b152019-02-01 14:15:57 -080086
87 # Press (or clear) one or more buttons (left/right)
Archie Pusaka3c9fd0c2021-04-13 15:26:46 +080088 CMD_MOUSE_BUTTON = 'B'
Neeraj Poojary59f8b152019-02-01 14:15:57 -080089 # Click the left and/or right button of the mouse
Archie Pusaka3c9fd0c2021-04-13 15:26:46 +080090 CMD_MOUSE_CLICK = 'C'
Neeraj Poojary59f8b152019-02-01 14:15:57 -080091 # Move the mouse along x and/or y axis
Archie Pusaka3c9fd0c2021-04-13 15:26:46 +080092 CMD_MOUSE_MOVE = 'M'
Neeraj Poojary59f8b152019-02-01 14:15:57 -080093 # Scrolling the mouse wheel up/down
Archie Pusaka3c9fd0c2021-04-13 15:26:46 +080094 CMD_MOUSE_SCROLL = 'S'
Neeraj Poojary59f8b152019-02-01 14:15:57 -080095
96 def GetCapabilities(self):
97 """What can this kit do/not do that tests need to adjust for?
98
99 Returns:
100 A dictionary from PeripheralKit.CAP_* strings to an appropriate value.
101 See above (CAP_*) for details.
102 """
103 return {PeripheralKit.CAP_TRANSPORTS: [PeripheralKit.TRANSPORT_LE],
104 PeripheralKit.CAP_HAS_PIN: False,
105 PeripheralKit.CAP_INIT_CONNECT: False}
106
107 def EnterCommandMode(self):
108 """Make the kit enter command mode.
109
110 The application on the nRF52 Dongle is always in command mode, so this
111 method will just create a serial connection if necessary
112
113 Returns:
114 True if the kit successfully entered command mode.
115
116 Raises:
117 nRF52Exception if there is an error in creating the serial connection
118 """
119 if self._serial is None:
120 self.CreateSerialDevice()
121 if not self._command_mode:
122 self._command_mode = True
123 return True
124
125 def LeaveCommandMode(self, force=False):
126 """Make the kit leave command mode.
127
128 As above, the nRF52 application is always in command mode.
129
130 Args:
131 force: True if we want to ignore potential errors and leave command mode
132 regardless of those errors
133
134 Returns:
135 True if the kit successfully left command mode.
136 """
137 if self._command_mode or force:
138 self._command_mode = False
139 return True
140
141 def Reboot(self):
142 """Reboot the nRF52 Dongle.
143
144 Does not erase the bond information.
145
146 Returns:
147 True if the kit rebooted successfully.
148 """
149 self.SerialSendReceive(self.CMD_REBOOT,
150 msg='rebooting nRF52')
151 time.sleep(self.RESET_SLEEP_SECS)
152 return True
153
154 def FactoryReset(self):
155 """Factory reset the nRF52 Dongle.
156
157 Erase the bond information and reboot.
158
159 Returns:
160 True if the kit is reset successfully.
161 """
162 self.SerialSendReceive(self.CMD_FACTORY_RESET,
163 msg='factory reset nRF52')
164 time.sleep(self.RESET_SLEEP_SECS)
165 return True
166
167 def GetAdvertisedName(self):
168 """Get the name advertised by the nRF52.
169
170 Returns:
171 The device name that the application uses in advertising
172 """
173 return self.SerialSendReceive(self.CMD_GET_ADVERTISED_NAME,
174 msg='getting advertised name')
175
176 def GetFirmwareVersion(self):
177 """Get the firmware version of the kit.
178
179 This is useful for checking what features are supported if we want to
180 support muliple versions of some kit.
181
182 For nRF52, returns the Link Layer Version (8 corresponds to BT 4.2),
183 Nordic Company ID (89), and Firmware ID (135).
184
185 Returns:
186 The firmware version of the kit.
187 """
188 return self.SerialSendReceive(self.CMD_GET_FIRMWARE_VERSION,
189 msg='getting firmware version')
190
191 def GetOperationMode(self):
192 """Get the operation mode.
193
194 This is master/slave in Bluetooth BR/EDR; the Bluetooth LE equivalent is
195 central/peripheral. For legacy reasons, we call it MASTER or SLAVE only.
196 Not all kits may support all modes.
197
198 nRF52 only supports peripheral role
199
200 Returns:
201 The operation mode of the kit.
202 """
203 logging.debug('GetOperationMode is a NOP on nRF52')
Archie Pusaka3c9fd0c2021-04-13 15:26:46 +0800204 return 'SLAVE'
Neeraj Poojary59f8b152019-02-01 14:15:57 -0800205
206 def SetMasterMode(self):
207 """Set the kit to master/central mode.
208
209 nRF52 application only acts as a peripheral
210
211 Returns:
212 True if master/central mode was set successfully.
213
214 Raises:
215 A kit-specific exception if master/central mode is unsupported.
216 """
217 error_msg = 'Failed to set master/central mode'
218 logging.error(error_msg)
219 raise nRF52Exception(error_msg)
220
221 def SetSlaveMode(self):
222 """Set the kit to slave/peripheral mode.
223
224 Silently succeeds, because the nRF52 application is always a peripheral
225
226 Returns:
227 True if slave/peripheral mode was set successfully.
228
229 Raises:
230 A kit-specific exception if slave/peripheral mode is unsupported.
231 """
232 logging.debug('SetSlaveMode is a NOP on nRF52')
233 return True
234
235 def GetAuthenticationMode(self):
236 """Get the authentication mode.
237
238 This specifies how the device will authenticate with the DUT, for example,
239 a PIN code may be used.
240
241 Not supported on nRF52 application.
242
243 Returns:
244 None as the nRF52 does not support an Authentication mode.
245 """
246 logging.debug('GetAuthenticationMode is a NOP on nRF52')
Archie Pusaka3c9fd0c2021-04-13 15:26:46 +0800247
Neeraj Poojary59f8b152019-02-01 14:15:57 -0800248
249 def SetAuthenticationMode(self, mode):
250 """Set the authentication mode to the specified mode.
251
252 If mode is PIN_CODE_MODE, implementations must ensure the default PIN
253 is set by calling _SetDefaultPinCode() as appropriate.
254
255 Not supported on nRF52 application.
256
257 Args:
258 mode: the desired authentication mode (specified in PeripheralKit)
259
260 Returns:
261 True if the mode was set successfully,
262
263 Raises:
264 A kit-specific exception if given mode is not supported.
265 """
266 error_msg = 'nRF52 does not support authentication mode'
267 logging.error(error_msg)
268 raise nRF52Exception(error_msg)
269
270 def GetPinCode(self):
271 """Get the pin code.
272
273 Returns:
274 A string representing the pin code,
275 None if there is no pin code stored.
276 """
277 warn_msg = 'nRF52 does not support PIN code mode, no PIN exists'
Archie Pusaka3c9fd0c2021-04-13 15:26:46 +0800278 logging.warning(warn_msg)
279
Neeraj Poojary59f8b152019-02-01 14:15:57 -0800280
281 def SetPinCode(self, pin):
282 """Set the pin code.
283
284 Not support on nRF52 application.
285
286 Returns:
287 True if the pin code is set successfully,
288
289 Raises:
290 A kit-specifc exception if the pin code is invalid.
291 """
292 error_msg = 'nRF52 does not support PIN code mode'
293 logging.error(error_msg)
294 raise nRF52Exception(error_msg)
295
296 def GetServiceProfile(self):
297 """Get the service profile.
298
299 Unrelated to HID for the nRF52 application, so ignore for now
300
301 Returns:
302 The service profile currently in use (as per constant in PeripheralKit)
303 """
304 logging.debug('GetServiceProfile is a NOP on nRF52')
Archie Pusaka3c9fd0c2021-04-13 15:26:46 +0800305 return 'HID'
Neeraj Poojary59f8b152019-02-01 14:15:57 -0800306
307 def SetServiceProfileSPP(self):
308 """Set SPP as the service profile.
309
310 Unrelated to HID for the nRF52 application, so ignore for now
311
312 Returns:
313 True if the service profile was set to SPP successfully.
314
315 Raises:
316 A kit-specifc exception if unsuppported.
317 """
318 error_msg = 'Failed to set SPP service profile'
319 logging.error(error_msg)
320 raise nRF52Exception(error_msg)
321
322 def SetServiceProfileHID(self):
323 """Set HID as the service profile.
324
325 nRF52 application only does HID at the moment. Silently succeeds
326
327 Returns:
328 True if the service profile was set to HID successfully.
329 """
330 logging.debug('SetServiceProfileHID is a NOP on nRF52')
331 return True
332
333 def GetLocalBluetoothAddress(self):
334 """Get the address advertised by the nRF52, which is the MAC address.
335
336 Address is returned as XX:XX:XX:XX:XX:XX
337
338 Returns:
339 The address of the nRF52 if successful or None if it fails
340 """
341 address = self.SerialSendReceive(self.CMD_GET_NRF52_MAC,
342 msg='getting local MAC address')
343 return address
344
345 def GetRemoteConnectedBluetoothAddress(self):
346 """Get the address of the device that is connected to the nRF52.
347
348 Address is returned as XX:XX:XX:XX:XX:XX
349 If not connected, nRF52 will return 00:00:00:00:00:00
350
351 Returns:
352 The address of the connected device or a null address if successful.
353 None if the serial receiving fails
354 """
355 address = self.SerialSendReceive(self.CMD_GET_REMOTE_CONNECTION_MAC,
356 msg='getting remote MAC address')
357 if len(address) == 17:
358 return address
359 else:
Archie Pusaka3c9fd0c2021-04-13 15:26:46 +0800360 logging.error('remote connection address is invalid: %s', address)
Neeraj Poojary59f8b152019-02-01 14:15:57 -0800361 return None
362
363 def GetConnectionStatus(self):
364 """Get whether the nRF52 is connected to another device.
365
366 nRF52 returns a string 'INVALID' or 'CONNECTED'
367
368 Returns:
369 True if the nRF52 is connected to another device
370 """
371 result = self.SerialSendReceive(self.CMD_GET_CONNECTION_STATUS,
372 msg = 'getting connection status')
373 return result == 'CONNECTED'
374
375 def EnableConnectionStatusMessage(self):
376 """Enable the connection status message.
377
378 On some kits, this is required to use connection-related methods.
379
380 Not supported by the nRF52 application for now. This could be
381 changed so that Connection Status Messages are sent by nRF52.
382
383 Returns:
384 True if enabling the connection status message successfully.
385 """
386 logging.debug('EnableConnectionStatusMessage is a NOP on nRF52')
387 return True
388
389 def DisableConnectionStatusMessage(self):
390 """Disable the connection status message.
391
392 Not supported by the nRF52 application for now. This could be
393 changed so that Connection Status Messages are sent by nRF52.
394
395 Returns:
396 True if disabling the connection status message successfully.
397 """
398 logging.debug('DisableConnectionStatusMessage is a NOP on nRF52')
399 return True
400
Joseph Hwang14140862020-01-10 16:25:02 +0800401 def GetDeviceType(self):
402 """Get the device type.
Neeraj Poojary59f8b152019-02-01 14:15:57 -0800403
404 Returns:
Joseph Hwang14140862020-01-10 16:25:02 +0800405 A string representing the device type
Neeraj Poojary59f8b152019-02-01 14:15:57 -0800406 """
407 return self.SerialSendReceive(self.CMD_GET_DEVICE_TYPE,
Joseph Hwang14140862020-01-10 16:25:02 +0800408 msg='getting the device type')
Neeraj Poojary59f8b152019-02-01 14:15:57 -0800409
410 def SetHIDType(self, device_type):
411 """Set HID type to the specified device type.
412
413 Args:
414 device_type: the HID type to emulate, from PeripheralKit
415 (MOUSE, KEYBOARD)
416
417 Returns:
418 True if successful
419
420 Raises:
421 A kit-specific exception if that device type is not supported.
422 """
423 if device_type == self.MOUSE:
424 result = self.SerialSendReceive(self.CMD_SET_MOUSE,
425 msg='setting mouse as HID type')
426 print(result)
427 elif device_type == self.KEYBOARD:
428 self.SerialSendReceive(self.CMD_SET_KEYBOARD,
429 msg='setting keyboard as HID type')
430 else:
Archie Pusaka3c9fd0c2021-04-13 15:26:46 +0800431 msg = 'Failed to set HID type, not supported: %s' % device_type
Neeraj Poojary59f8b152019-02-01 14:15:57 -0800432 logging.error(msg)
433 raise nRF52Exception(msg)
434 return True
435
436 def GetClassOfService(self):
437 """Get the class of service, if supported.
438
439 Not supported on nRF52
440
441 Returns:
442 None, the only reasonable value for BLE-only devices
443 """
444 logging.debug('GetClassOfService is a NOP on nRF52')
Archie Pusaka3c9fd0c2021-04-13 15:26:46 +0800445
Neeraj Poojary59f8b152019-02-01 14:15:57 -0800446
447 def SetClassOfService(self, class_of_service):
448 """Set the class of service, if supported.
449
450 The class of service is a number usually assigned by the Bluetooth SIG.
451 Usually supported only on BR/EDR kits.
452
453 Not supported on nRF52, but fake it
454
455 Args:
456 class_of_service: A decimal integer representing the class of service.
457
458 Returns:
459 True as this action is not supported.
460 """
461 logging.debug('SetClassOfService is a NOP on nRF52')
462 return True
463
464 def GetClassOfDevice(self):
465 """Get the class of device, if supported.
466
467 The kit uses a hexadeciaml string to represent the class of device.
468 It is converted to a decimal number as the return value.
469 The class of device is a number usually assigned by the Bluetooth SIG.
470 Usually supported only on BR/EDR kits.
471
472 Not supported on nRF52, so None
473
474 Returns:
475 None, the only reasonable value for BLE-only devices.
476 """
477 logging.debug('GetClassOfDevice is a NOP on nRF52')
Archie Pusaka3c9fd0c2021-04-13 15:26:46 +0800478
Neeraj Poojary59f8b152019-02-01 14:15:57 -0800479
480 def SetClassOfDevice(self, device_type):
481 """Set the class of device, if supported.
482
483 The class of device is a number usually assigned by the Bluetooth SIG.
484 Usually supported only on BR/EDR kits.
485
486 Not supported on nRF52, but fake it.
487
488 Args:
489 device_type: A decimal integer representing the class of device.
490
491 Returns:
492 True as this action is not supported.
493 """
494 logging.debug('SetClassOfDevice is a NOP on nRF52')
495 return True
496
497 def SetRemoteAddress(self, remote_address):
498 """Set the remote Bluetooth address.
499
500 (Usually this will be the device under test that we want to connect with,
501 where the kit starts the connection.)
502
503 Not supported on nRF52 HID application.
504
505 Args:
506 remote_address: the remote Bluetooth MAC address, which must be given as
507 12 hex digits with colons between each pair.
508 For reference: '00:29:95:1A:D4:6F'
509
510 Returns:
511 True if the remote address was set successfully.
512
513 Raises:
514 PeripheralKitException if the given address was malformed.
515 """
516 error_msg = 'Failed to set remote address'
517 logging.error(error_msg)
518 raise nRF52Exception(error_msg)
519
520 def Connect(self):
521 """Connect to the stored remote bluetooth address.
522
523 In the case of a timeout (or a failure causing an exception), the caller
524 is responsible for retrying when appropriate.
525
526 Not supported on nRF52 HID application.
527
528 Returns:
529 True if connecting to the stored remote address succeeded, or
530 False if a timeout occurs.
531 """
532 error_msg = 'Failed to connect to remote device'
533 logging.error(error_msg)
534 raise nRF52Exception(error_msg)
535
536 def Disconnect(self):
537 """Disconnect from the remote device.
538
539 Specifically, this causes the peripheral emulation kit to disconnect from
540 the remote connected device, usually the DUT.
541
542 Returns:
543 True if disconnecting from the remote device succeeded.
544 """
545 self.SerialSendReceive(self.CMD_DISCONNECT,
546 msg='disconnect')
547 return True
548
Archie Pusaka3c9fd0c2021-04-13 15:26:46 +0800549 def Discover(self, remote_address):
550 """Discover the remote address.
551
552 Not supported on nRF52 HID application.
553
554 Args:
555 remote_address: the remote Bluetooth address, which must be given as 12
556 hex digits with colons between each pair.
557 For reference: '00:29:95:1A:D4:6F'
558
559 Returns:
560 True if discovering the remote address succeeded
561 """
562 error_msg = 'nRF52 does not support discovery'
563 logging.error(error_msg)
564 raise nRF52Exception(error_msg)
565
Neeraj Poojary59f8b152019-02-01 14:15:57 -0800566 def StartAdvertising(self):
567 """Command the nRF52 to begin advertising with its current settings.
568
569 Returns:
570 True if successful.
571 """
572 self.SerialSendReceive(self.CMD_START_ADVERTISING,
573 msg='start advertising')
574 return True
575
576 def MouseMove(self, delta_x, delta_y):
577 """Move the mouse (delta_x, delta_y) steps.
578
579 Buttons currently pressed will stay pressed during this operation.
580 This move is relative to the current position by the HID standard.
581 Valid step values must be in the range [-127,127].
582
583 Args:
584 delta_x: The number of steps to move horizontally.
585 Negative values move left, positive values move right.
586 delta_y: The number of steps to move vertically.
587 Negative values move up, positive values move down.
588
589 Returns:
590 True if successful.
591 """
592 command = self.CMD_MOUSE_MOVE + self.CMD_FS
593 command += str(delta_x) + self.CMD_FS + str(delta_y)
Archie Pusaka3c9fd0c2021-04-13 15:26:46 +0800594 message = 'moving BLE mouse ' + str(delta_x) + ' ' + str(delta_y)
595 self.SerialSendReceive(command, msg=message)
Neeraj Poojary59f8b152019-02-01 14:15:57 -0800596 return True
597
598 def MouseScroll(self, steps):
599 """Scroll the mouse wheel steps number of steps.
600
601 Buttons currently pressed will stay pressed during this operation.
602 Valid step values must be in the range [-127,127].
603
604 Args:
605 steps: The number of steps to scroll the wheel.
606 With traditional scrolling:
607 Negative values scroll down, positive values scroll up.
608 With reversed (formerly "Australian") scrolling this is reversed.
609
610 Returns:
611 True if successful.
612 """
613 command = self.CMD_MOUSE_SCROLL + self.CMD_FS
614 command += self.CMD_FS
615 command += str(steps) + self.CMD_FS
616 message = 'scrolling BLE mouse'
Archie Pusaka3c9fd0c2021-04-13 15:26:46 +0800617 self.SerialSendReceive(command, msg=message)
Neeraj Poojary59f8b152019-02-01 14:15:57 -0800618 return True
619
620 def MouseHorizontalScroll(self, steps):
621 """Horizontally scroll the mouse wheel steps number of steps.
622
623 Buttons currently pressed will stay pressed during this operation.
624 Valid step values must be in the range [-127,127].
625
626 There is no nRF52 limitation for implementation. If we can program
627 the correct HID event report to emulate horizontal scrolling, this
628 can be supported.
Archie Pusaka3c9fd0c2021-04-13 15:26:46 +0800629
Neeraj Poojary59f8b152019-02-01 14:15:57 -0800630 **** Not implemented ****
Archie Pusaka3c9fd0c2021-04-13 15:26:46 +0800631
Neeraj Poojary59f8b152019-02-01 14:15:57 -0800632 Args:
633 steps: The number of steps to scroll the wheel.
634 With traditional scrolling:
635 Negative values scroll left, positive values scroll right.
636 With reversed (formerly "Australian") scrolling this is reversed.
637
638 Returns:
639 True if successful.
640 """
Archie Pusaka3c9fd0c2021-04-13 15:26:46 +0800641
642 del steps # to silent linter warning
Neeraj Poojary59f8b152019-02-01 14:15:57 -0800643 return True
644
645 def _MouseButtonCodes(self):
646 """Gives the letter codes for whatever buttons are pressed.
647
648 Returns:
649 A int w/ bits representing pressed buttons.
650 """
651 currently_pressed = 0
652 for button in self._buttons_pressed:
653 if button == PeripheralKit.MOUSE_BUTTON_LEFT:
654 currently_pressed += self.MOUSE_BUTTON_LEFT_BIT
655 elif button == PeripheralKit.MOUSE_BUTTON_RIGHT:
656 currently_pressed += self.MOUSE_BUTTON_RIGHT_BIT
657 else:
Archie Pusaka3c9fd0c2021-04-13 15:26:46 +0800658 error = 'Unknown mouse button in state: %s' % button
Neeraj Poojary59f8b152019-02-01 14:15:57 -0800659 logging.error(error)
660 raise nRF52Exception(error)
661 return currently_pressed
662
663 def MousePressButtons(self, buttons):
664 """Press the specified mouse buttons.
665
666 The kit will continue to press these buttons until otherwise instructed, or
667 until its state has been reset.
668
669 Args:
670 buttons: A set of buttons, as PeripheralKit MOUSE_BUTTON_* values, that
671 will be pressed (and held down).
672
673 Returns:
674 True if successful.
675 """
676 self._MouseButtonStateUnion(buttons)
677 button_codes = self._MouseButtonCodes()
678 command = self.CMD_MOUSE_BUTTON + self.CMD_FS
679 command += str(button_codes)
680 message = 'pressing BLE mouse buttons'
Archie Pusaka3c9fd0c2021-04-13 15:26:46 +0800681 self.SerialSendReceive(command, msg=message)
Neeraj Poojary59f8b152019-02-01 14:15:57 -0800682 return True
683
684 def MouseReleaseAllButtons(self):
685 """Release all mouse buttons.
686
687 Returns:
688 True if successful.
689 """
690 self._MouseButtonStateClear()
691 command = self.CMD_MOUSE_BUTTON + self.CMD_FS
692 command += '0'
693 message = 'releasing all BLE HOG mouse buttons'
Archie Pusaka3c9fd0c2021-04-13 15:26:46 +0800694 self.SerialSendReceive(command, msg=message)
Neeraj Poojary59f8b152019-02-01 14:15:57 -0800695 return True
696
Archie Pusaka3c9fd0c2021-04-13 15:26:46 +0800697 def SetDiscoverable(self, discoverable):
698 """Sets the discoverability of the device.
699
700 Not supported on nRF52 application.
701
702 Args:
703 discoverable: Whether device is discoverable/advertising.
704 """
705 error_msg = 'nRF52 does not support discoverable'
706 logging.error(error_msg)
707 raise nRF52Exception(error_msg)
708
Neeraj Poojary59f8b152019-02-01 14:15:57 -0800709 def Reset(self):
Archie Pusaka3c9fd0c2021-04-13 15:26:46 +0800710 self.SerialSendReceive(nRF52.CMD_REBOOT, msg='reset nRF52')
Neeraj Poojary59f8b152019-02-01 14:15:57 -0800711 return True
712
713 def SetModeMouse(self):
714 self.EnterCommandMode()
Archie Pusaka3c9fd0c2021-04-13 15:26:46 +0800715 self.SerialSendReceive(nRF52.CMD_SET_MOUSE, msg='set nRF52 mouse')
Neeraj Poojary59f8b152019-02-01 14:15:57 -0800716 return True
717
718 def GetKitInfo(self, connect_separately=False, test_reset=False):
719 """A simple demo of getting kit information."""
720 if connect_separately:
721 print('create serial device: %s' % self.CreateSerialDevice())
722 if test_reset:
723 print('factory reset: %s' % self.FactoryReset())
724 self.EnterCommandMode()
725 print('advertised name: %s' % self.GetAdvertisedName())
726 print('firmware version: %s' % self.GetFirmwareVersion())
727 print('local bluetooth address: %s' % self.GetLocalBluetoothAddress())
728 print('connection status: %s' % self.GetConnectionStatus())
729 # The class of service/device is None for LE kits (it is BR/EDR-only)
730
731
732if __name__ == '__main__':
733 kit_instance = nRF52()
734 kit_instance.GetKitInfo()