The following code snippets can be used when operating in Command Mode to perform specific tasks.
Heart Rate Monitor Service
The command list below will add a Heart Rate service to the BLEFriend's attribute table, with two characteristics:
# Perform a factory reset to make sure we get a clean start AT+FACTORYRESET OK # Add the Heart Rate service entry AT+GATTADDSERVICE=UUID=0x180D 1 OK # Add the Heart Rate Measurement characteristic AT+GATTADDCHAR=UUID=0x2A37, PROPERTIES=0x10, MIN_LEN=2, MAX_LEN=3, VALUE=00-40 1 OK # Add the Body Sensor Location characteristic AT+GATTADDCHAR=UUID=0x2A38, PROPERTIES=0x02, MIN_LEN=1, VALUE=3 2 OK # Create a custom advertising packet that includes the Heart Rate service UUID AT+GAPSETADVDATA=02-01-06-05-02-0d-18-0a-18 OK # Reset the device to start advertising with the custom payload ATZ OK # Update the value of the heart rate measurement (set it to 0x004A) AT+GATTCHAR=1,00-4A OK
Python Script
The following code performs the same function, but has been placed inside a Python wrapper using PySerial to show how you can script actions for the AT parser.
import io
import sys
import serial
import random
from time import sleep
filename = "hrm.py"
ser = None
serio = None
verbose = True # Set this to True to see all of the incoming serial data
def usage():
"""Displays information on the command-line parameters for this script"""
print "Usage: " + filename + " <serialPort>\n"
print "For example:\n"
print " Windows : " + filename + " COM14"
print " OS X : " + filename + " /dev/tty.usbserial-DN009WNO"
print " Linux : " + filename + " /dev/ttyACM0"
return
def checkargs():
"""Validates the command-line arguments for this script"""
if len(sys.argv) < 2:
print "ERROR: Missing serialPort"
usage()
sys.exit(-1)
if len(sys.argv) > 2:
print "ERROR: Too many arguments (expected 1)."
usage()
sys.exit(-2)
def errorhandler(err, exitonerror=True):
"""Display an error message and exit gracefully on "ERROR\r\n" responses"""
print "ERROR: " + err.message
if exitonerror:
ser.close()
sys.exit(-3)
def atcommand(command, delayms=0):
"""Executes the supplied AT command and waits for a valid response"""
serio.write(unicode(command + "\n"))
if delayms:
sleep(delayms/1000)
rx = None
while rx != "OK\r\n" and rx != "ERROR\r\n":
rx = serio.readline(2000)
if verbose:
print unicode(rx.rstrip("\r\n"))
# Check the return value
if rx == "ERROR\r\n":
raise ValueError("AT Parser reported an error on '" + command.rstrip() + "'")
if __name__ == '__main__':
# Make sure we received a single argument (comPort)
checkargs()
# This will automatically open the serial port (no need for ser.open)
ser = serial.Serial(port=sys.argv[1], baudrate=9600, rtscts=True)
serio = io.TextIOWrapper(io.BufferedRWPair(ser, ser, 1),
newline='\r\n',
line_buffering=True)
# Add the HRM service and characteristic definitions
try:
atcommand("AT+FACTORYRESET", 1000) # Wait 1s for this to complete
atcommand("AT+GATTCLEAR")
atcommand("AT+GATTADDSERVICE=UUID=0x180D")
atcommand("AT+GATTADDCHAR=UUID=0x2A37, PROPERTIES=0x10, MIN_LEN=2, MAX_LEN=3, VALUE=00-40")
atcommand("AT+GATTADDCHAR=UUID=0x2A38, PROPERTIES=0x02, MIN_LEN=1, VALUE=3")
atcommand("AT+GAPSETADVDATA=02-01-06-05-02-0d-18-0a-18")
# Perform a system reset and wait 1s to come back online
atcommand("ATZ", 1000)
# Update the value every second
while True:
atcommand("AT+GATTCHAR=1,00-%02X" % random.randint(50, 100), 1000)
except ValueError as err:
# One of the commands above returned "ERROR\n"
errorhandler(err)
except KeyboardInterrupt:
# Close gracefully on CTRL+C
ser.close()
sys.exit()
The results of this script can be seen below in the 'HRM' app of Nordic's nRF Toolbox application:
Please note that nRF Toolbox will only display HRM data if the value changes, so you will need to update the Heart Rate Measurement characteristic at least once after opening the HRM app and connecting to the BLEFriend
Page last edited November 13, 2014
Text editor powered by tinymce.