code.py
  1  # SPDX-FileCopyrightText: 2020 Carter Nelson for Adafruit Industries
  2  #
  3  # SPDX-License-Identifier: MIT
  4  
  5  import time
  6  import displayio
  7  import terminalio
  8  from adafruit_clue import clue
  9  from adafruit_display_text import label
 10  import adafruit_imageload
 11  from adafruit_ble import BLERadio
 12  from adafruit_ble.advertising.standard import ProvideServicesAdvertisement
 13  from adafruit_ble.services.nordic import UARTService
 14  
 15  #--| User Config |---------------------------------------------------
 16  MY_NAME = "ME"
 17  FRIENDS_NAME = "FRIEND"
 18  #--| User Config |---------------------------------------------------
 19  
 20  WAIT_FOR_DOUBLE = 0.05
 21  DEBOUNCE = 0.25
 22  
 23  # Define Morse Code dictionary
 24  morse_code = {
 25      ".-"   : "A", "-..." : "B", "-.-." : "C", "-.."  : "D", "."    : "E",
 26      "..-." : "F", "--."  : "G", "...." : "H", ".."   : "I", ".---" : "J",
 27      "-.-"  : "K", ".-.." : "L", "--"   : "M", "-."   : "N", "---"  : "O",
 28      ".--." : "P", "--.-" : "Q", ".-."  : "R", "..."  : "S", "-"    : "T",
 29      "..-"  : "U", "...-" : "V", ".--"  : "W", "-..-" : "X", "-.--" : "Y",
 30      "--.." : "Z",
 31  }
 32  
 33  # BLE Radio Stuff
 34  ble = BLERadio()
 35  uart_service = UARTService()
 36  advertisement = ProvideServicesAdvertisement(uart_service)
 37  ble._adapter.name = MY_NAME #pylint: disable=protected-access
 38  
 39  # Display Stuff
 40  display = clue.display
 41  disp_group = displayio.Group()
 42  display.show(disp_group)
 43  
 44  # Background BMP with the Morse Code cheat sheet
 45  bmp, pal = adafruit_imageload.load("morse_bg.bmp",
 46                                     bitmap=displayio.Bitmap,
 47                                     palette=displayio.Palette)
 48  disp_group.append(displayio.TileGrid(bmp, pixel_shader=pal))
 49  
 50  # Incoming messages show up here
 51  in_label = label.Label(terminalio.FONT, text='A'*18, scale=2,
 52                         color=0x000000)
 53  in_label.anchor_point = (0.5, 0)
 54  in_label.anchored_position = (65, 12)
 55  disp_group.append(in_label)
 56  
 57  # Outging messages show up here
 58  out_label = label.Label(terminalio.FONT, text='B'*18, scale=2,
 59                          color=0x000000)
 60  out_label.anchor_point = (0.5, 0)
 61  out_label.anchored_position = (65, 190)
 62  disp_group.append(out_label)
 63  
 64  # Morse Code entry happens here
 65  edit_label = label.Label(terminalio.FONT, text='....', scale=2,
 66                           color=0x000000)
 67  edit_label.anchor_point = (0.5, 0)
 68  edit_label.anchored_position = (105, 222)
 69  disp_group.append(edit_label)
 70  
 71  def scan_and_connect():
 72      '''
 73      Advertise self while scanning for friend. If friend is found, can
 74      connect by pressing A+B buttons. If friend connects first, then
 75      just stop.
 76  
 77      Return is a UART object that can be used for read/write.
 78      '''
 79  
 80      print("Advertising.")
 81      central = False
 82      ble.start_advertising(advertisement)
 83  
 84      print("Waiting.")
 85      friend = None
 86      while not ble.connected:
 87  
 88          if friend is None:
 89              print("Scanning.")
 90              in_label.text = out_label.text = "Scanning..."
 91              for adv in ble.start_scan():
 92                  if ble.connected:
 93                      # Friend connected with us, we're done
 94                      ble.stop_scan()
 95                      break
 96                  if adv.complete_name == FRIENDS_NAME:
 97                      # Found friend, can stop scanning
 98                      ble.stop_scan()
 99                      friend = adv
100                      print("Found", friend.complete_name)
101                      in_label.text = "Found {}".format(friend.complete_name)
102                      out_label.text = "A+B to connect"
103                      break
104          else:
105              if clue.button_a and clue.button_b:
106                  # Connect to friend
107                  print("Connecting to", friend.complete_name)
108                  ble.connect(friend)
109                  central = True
110  
111      # We're now connected, one way or the other
112      print("Stopping advertising.")
113      ble.stop_advertising()
114  
115      # Return a UART object to use
116      if central:
117          print("Central - using my UART service.")
118          return uart_service
119      else:
120          print("Peripheral - connecting to their UART service.")
121          for connection in ble.connections:
122              if UARTService not in connection:
123                  continue
124              return connection[UARTService]
125  
126  #--------------------------
127  # The main application loop
128  #--------------------------
129  while True:
130  
131      # Establish initial connection
132      uart = scan_and_connect()
133  
134      print("Connected.")
135  
136      code = ''
137      in_label.text = out_label.text = ' '*18
138      edit_label.text = ' '*4
139      done = False
140  
141      # Run the chat while connected
142      while ble.connected:
143  
144          # Check for incoming message
145          incoming_bytes = uart.in_waiting
146          if incoming_bytes:
147              bytes_in = uart.read(incoming_bytes)
148              print("Received: ", bytes_in)
149              in_label.text = in_label.text[incoming_bytes:] + bytes_in.decode()
150  
151          # DOT (or done)
152          if clue.button_a:
153              start = time.monotonic()
154              while time.monotonic() - start < WAIT_FOR_DOUBLE:
155                  if clue.button_b:
156                      done = True
157              if not done and len(code) < 4:
158                  print('.', end='')
159                  code += '.'
160                  edit_label.text = "{:4s}".format(code)
161                  time.sleep(DEBOUNCE)
162  
163          # DASH (or done)
164          if clue.button_b:
165              start = time.monotonic()
166              while time.monotonic() - start < WAIT_FOR_DOUBLE:
167                  if clue.button_a:
168                      done = True
169              if not done and len(code) < 4:
170                  print('-', end='')
171                  code += '-'
172                  edit_label.text = "{:4s}".format(code)
173                  time.sleep(DEBOUNCE)
174  
175          # Turn Morse Code into letter and send
176          if done:
177              letter = morse_code.get(code, ' ')
178              print(' >', letter)
179              out_label.text = out_label.text[1:] + letter
180              uart.write(str.encode(letter))
181              code = ''
182              edit_label.text = ' '*4
183              done = False
184              time.sleep(DEBOUNCE)
185  
186      print("Disconnected.")