Summary

In this article I update the AnyCloud BLE advertising scanner to use the btutil library that was created in the previous post.  In addition, I add a command queue to the bluetoothManger and enable a new command to turn on and off scanning.

Story

If you have been following along until now, which I imagine that you have if you are reading this,  you will have gotten a vomit of device data blasting out onto your serial console.  This isn’t very helpful.  So now what?  I am going to divide this problem into two parts

  1. Creating a new user command to turn on and off scanning (this article)
  2. Creating a database to manage the data + a set of commands to dump it (next article)

For this series of articles I will:

  1. Discuss an overview of Bluetooth Application Architecture (Part 1)
  2. Explain how to Start the AnyCloud Bluetooth Stack (Part 1) 
    1. Discuss the configuration structure: bt_platform_cfg_setting (Part 1)
    2. Discuss the configuration structure: wiced_bt_cfg_settings (Part 1)
    3. Discuss the Tasks created by the Bluetooth Stack (Part 1)
    4. Build the Basic Project (Part 2)
    5. Explain BLE Advertising - Scanner/Observer (Part 3)
    6. Explain BLE Advertising - Advertise (Part 3)
    7. How does scanning work in the AnyCloud Bluetooth Stack?  (Part 3)
    8. Add Observing to our Project  (Part 3)
    9. Program and Test the Project  (Part 3)
    10. Add the IoT Expert Bluetooth Utility Library (Part 4)
    11. Mulithreading Dangers (Part 4)
    12. Add a Queue to the Bluetooth Manager Thread (Part 4)
    13. Add a Timer to Process the Queue (Part 4)
    14. A Potential Threading Bug (Part 4)
    15. Add a Scan Off & On Command (Part 4)
    16. Create an Advertising Data Database Task (Part 5)
    17. Update the Advertising Database to Accept Submitted ADV Packets (Part 5)
    18. Update the Bluetooth Manager to Submit Adv Packets (Part 5)
    19. Create an Advertising Data Database (Part 5)
    20. Add a Command to Print the Database (Part 5)
    21. Refactor a silly duplication (Part 6)
    22. Update the print (Part 6)
    23. Add the "decode" command (Part 6)
    24. Add the decode packets functionality (Part 6)
    25. Program and test (Part 6)
    26. Design a new advertising database (Part 7)
    27. Update to the new database (Part 7)
    28. Update printing (Part 7)
    29. Update the advertising add (Part 7)
    30. Create a watch command (Part 7)
    31. Create a record command (Part 7)
    32. Create an erase command (Part 7)
    33. Update the filter data structure (Part 8)
    34. Fix the Add function (Part 8)
    35. Add the filter command (Part 8)
    36. Update the printing (Part 8)
    37. Fix a memory leak (Part 9)
    38. Add packet age (Part 9)
    39. Fix the printing, again (Part 9)
    40. Fix the add packet function (Part 9)
    41. Update the database structure for sort and purge (Part 10)
    42. Add the sort and purge commands (Part 10)
    43. Add the sort functionality (Part 10)
    44. Add the purge functionality (Part 10)
    45. The End & Commentary (Part 10)

    All of the code can be found at git@github.com:iotexpert/AnyCloudBLEScanner.git and https://github.com/iotexpert/AnyCloudBLEScanner.git

    There are git tags in place starting at part 5 so that you can look at just that version of the code.  "git tag" to list the tags.  And "git checkout part6" to look at the part 6 version of the code.

    Add the IoT Expert “btutil” Library

    Before we actually start all of the command queue stuff, lets move to the btutil library that I talked about in the previous post.  To do this, add the library using the library manager.

    Then delete bt_platform_cfg_settings.h and bt_platform_cfg_settings.c from your project.  Finally Rebuild and make sure that everything still works.  That is it.

    Multithreading

    Id like to explain that there is now some danger.  That danger comes from the fact that we have multiple tasks which are all accessing data plus functions that are talking to each other ASYNCHRONOUSLY.  Specifically we have:

    1. The Bluetooth Stack task – running the Bluetooth stack and management callback
    2. The Bluetooth Stack APIs – e.g. wiced_bt_ble_observe
    3. The usrcmd task – which is interacting with the user on the serial port and talking to the other tasks
    4. A timer_svc task – which runs software timers
    5. The advertising data (which I will start saving in the next article)

    When faced with this situation what I typically like to do is provide thread safe public functions for each of the tasks.  Then any other task can call these functions and know that things are not going to get corrupted by a race condition.

    To make the design thread safe, I typically like to put an RTOS Queue between the tasks.  These queues are a safe place to send and receive data in a “thread safe” way.  There are two basic design patterns that can be used

    1. Define a message structure (that gets pushed into the queue) and make it global (via a dot-h).  Define a queue handle and make it global (via a dot-h).  Then let any task build messages and push them into the queue to be received in the task that owns the queue.
    2. Define the message structure and queue.  Then define functions which are global (via a dot-h) which know how to interact with the queue.

    I typically think that the 2nd method is better, so that is what I am going to do here.

    1. In BluetoothManager.h I will provide a function called “btm_cmdScan”
    2. The usrcmd task will call the btm_cmdScan function which will
    3. Create a btm_cmdMsg_t with the “scan” command and data of true/false
    4. Then push it into the Bluetooth Manager Command Queue
    5. Where a timer callback in the Bluetooth Manager Task will take it out of the queue
    6. Figure out that it is a “scan” command
    7. Then will either turn on or off scanning

    Add a Queue to the Bluetooth Manager Thread

    So we need two things a message to push into a queue (just a structure) and we need a queue to push it into.  First the message which is just a structure with two elements.  The first element is a command and the second element is some data of type void.  The meaning of the void *data will be different based on the command.

    But how about the command?  The command is just an enumerate list of commands which will now start with just one command.

    And know we need to define the queue.

    Before you can use the queue you need to initialize it.  The best place to initialize this queue is in the management callback right after the stack gets going.  You can see that I tell FreeRTOS that there is a queue which can hold up to 10 commands.  I also tell it that each command is the sizeof the command message.

    Now we need to create a way for other tasks to create these command messages.  They will do this by calling a function which we will define in the bluetoothManager.h

    This function will live in bluetoothManager.c and it simply

    1. Creates a command
    2. Set the actual command to scan
    3. Sets the void* data to be enable … in other words start or stop scanning.  Remember that a void * can be anything.  See I cast a bool to a void *
    4. Finally push the data into the command queue

    Add a Timer to Process the Queue

    So now we have a method to push items into the queue.  How do we get them out of the queue?  To do that I will use a Bluetooth Stack timer that will run every 50ms.

    First, define the timer in bluetoothManager.c

    Then define a function which the timer will call.  This function will

    1. Try to get a message out of the queue
    2. IF there is a message it will use a big switch to look at the possible messages
    3. If the message is a scan
    4. Then call the wiced function to either start “observing” or stop “observing”

    The last thing you need to do is start the timer.  The best place to start the timer is in the management callback where you need to

    1. Create the timer
    2. Tell it to start and run every 50ms

    A Potential Threading Bug

    When I did the implementation originally I created what I thought was a threading bug.  Specifically I used the FreeRTOS timer to process the queue.  In other words instead of using a wiced_timer_ext_t I used a TimerHandle_t.  So what?

    The wiced_timer_ext_t is run INSIDE of the BluetoothStack task where the TimerHandle_t is run inside of the Timer_SVC task.

    So what?  I was afraid that the call to wiced_bt_ble_obsere was NOT thread safe and needed to be called inside of the same task as the stack.

    After some digging I found out that the Bluetooth Stack is threadsafe, so I worried for no reason.  Well, actually, you can never worry enough about making these kinds of threading bugs because they are viscously difficult to debug.

    Add a Scan Off & On Command

    The last thing that you need to do is add an actual command to the usercmd task to call the bluetooth manager function to turn on and off scanning.

    First, add a new prototype for your new command in usercmd.c.  Then add it to the list of legal commands.

    Then create the function to process the command line input and call the btm_scan function.

    Now build it and run it.  You should still get adv packets barfing all over your screen.  But now you can turn on and off the scanning with “scan on” and “scan off”.  In the next article we will create a database to hold the scan packets.

    Recommended Posts

    No comment yet, add your voice below!


    Add a Comment

    Your email address will not be published. Required fields are marked *