New Air Quality Demo using BLE
Project: http://git-wip-us.apache.org/repos/asf/incubator-mynewt-site/repo Commit: http://git-wip-us.apache.org/repos/asf/incubator-mynewt-site/commit/443e26ac Tree: http://git-wip-us.apache.org/repos/asf/incubator-mynewt-site/tree/443e26ac Diff: http://git-wip-us.apache.org/repos/asf/incubator-mynewt-site/diff/443e26ac Branch: refs/heads/develop Commit: 443e26ac9120c44b5ba92c2b14d4cc384200a53b Parents: c250d96 Author: David G. Simmons <[email protected]> Authored: Mon Jan 16 11:52:42 2017 -0500 Committer: David G. Simmons <[email protected]> Committed: Tue Jan 17 10:15:48 2017 -0500 ---------------------------------------------------------------------- docs/os/tutorials/air_quality_ble.md | 221 +++++++++++++++++++++ docs/os/tutorials/pics/MyNewtSensorReader.jpg | Bin 0 -> 141358 bytes mkdocs.yml | 4 +- 3 files changed, 224 insertions(+), 1 deletion(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/incubator-mynewt-site/blob/443e26ac/docs/os/tutorials/air_quality_ble.md ---------------------------------------------------------------------- diff --git a/docs/os/tutorials/air_quality_ble.md b/docs/os/tutorials/air_quality_ble.md new file mode 100644 index 0000000..cc2cbb7 --- /dev/null +++ b/docs/os/tutorials/air_quality_ble.md @@ -0,0 +1,221 @@ +## Air quality sensor project via Bluetooth + +This is a follow-on project to the [Basic Air Quality Sensor](air_quality_esnsor.md) project so it is +assumed that you have worked through that project and have your CO2 sensor working properly with +your Arduino Primo board. + +So let's get started making this thing Bluetooth enabled! + +### Add Bluetooth GATT Services + +Since we already built the previous demo on the [bluetooth peripheral](bleprph/bleprph-app.md) basic +app most of the bluetooth plumbing has already been taken care of for us. What's left is for us +to add the required GATT services for advertising the Carbon Dioxide sensor so that +other devices can get those values. + +First, we'll define the GATT Serivces in `apps/air_quality/src/bleprph.h` + +```c +/* Sensor Data */ +/* e761d2af-1c15-4fa7-af80-b5729002b340 */ +static const uint8_t gatt_svr_svc_co2_uuid[16] = { + 0x40, 0xb3, 0x20, 0x90, 0x72, 0xb5, 0x80, 0xaf, + 0xa7, 0x4f, 0x15, 0x1c, 0xaf, 0xd2, 0x61, 0xe7 }; +#define CO2_SNS_TYPE 0xDEAD +#define CO2_SNS_STRING "SenseAir K30 CO2 Sensor" +#define CO2_SNS_VAL 0xBEAD + +uint16_t gatt_co2_val; +``` + +You can use any hex values you choose for the sensor type and sensor values, and you can +even forgoe the sensor type and sensor string definitions altogether but they make +the results look nice in our Bleutooth App. + +Next well add those services to `apps/air_quality/src/gatt_svr.c` + +```c +static int +gatt_svr_sns_access(uint16_t conn_handle, uint16_t attr_handle, + struct ble_gatt_access_ctxt *ctxt, + void *arg); + +static uint16_t gatt_co2_val_len; + +``` + +And make sure it is added as *primary* service + +```c +static const struct ble_gatt_svc_def gatt_svr_svcs[] = { + { + /*** Service: Security test. */ + .type = BLE_GATT_SVC_TYPE_PRIMARY, + .uuid128 = gatt_svr_svc_sec_test_uuid, + .characteristics = (struct ble_gatt_chr_def[]) { { + /*** Characteristic: Random number generator. */ + .uuid128 = gatt_svr_chr_sec_test_rand_uuid, + .access_cb = gatt_svr_chr_access_sec_test, + .flags = BLE_GATT_CHR_F_READ | BLE_GATT_CHR_F_READ_ENC, + }, { + /*** Characteristic: Static value. */ + .uuid128 = gatt_svr_chr_sec_test_static_uuid, + .access_cb = gatt_svr_chr_access_sec_test, + .flags = BLE_GATT_CHR_F_READ | + BLE_GATT_CHR_F_WRITE | BLE_GATT_CHR_F_WRITE_ENC, + }, { + 0, /* No more characteristics in this service. */ + } }, + }, + { + /*** CO2 Level Notification Service. */ + .type = BLE_GATT_SVC_TYPE_PRIMARY, + .uuid128 = gatt_svr_svc_co2_uuid, + .characteristics = (struct ble_gatt_chr_def[]) { { + .uuid128 = BLE_UUID16(CO2_SNS_TYPE), + .access_cb = gatt_svr_sns_access, + .flags = BLE_GATT_CHR_F_READ, + }, { + .uuid128 = BLE_UUID16(CO2_SNS_VAL), + .access_cb = gatt_svr_sns_access, + .flags = BLE_GATT_CHR_F_NOTIFY, + }, { + 0, /* No more characteristics in this service. */ + } }, + }, + { + 0, /* No more services. */ + }, +}; +``` + +Next we need to tell the GATT Server how to handle requests for CO2 readings : + +```c +static int +gatt_svr_sns_access(uint16_t conn_handle, uint16_t attr_handle, + struct ble_gatt_access_ctxt *ctxt, + void *arg) +{ + uint16_t uuid16; + int rc; + + uuid16 = ble_uuid_128_to_16(ctxt->chr->uuid128); + assert(uuid16 != 0); + + switch (uuid16) { + case CO2_SNS_TYPE: + assert(ctxt->op == BLE_GATT_ACCESS_OP_READ_CHR); + rc = os_mbuf_append(ctxt->om, CO2_SNS_STRING, sizeof CO2_SNS_STRING); + BLEPRPH_LOG(INFO, "CO2 SENSOR TYPE READ: %s\n", CO2_SNS_STRING); + return rc == 0 ? 0 : BLE_ATT_ERR_INSUFFICIENT_RES; + + case CO2_SNS_VAL: + if (ctxt->op == BLE_GATT_ACCESS_OP_WRITE_CHR) { + rc = gatt_svr_chr_write(ctxt->om, 0, + sizeof gatt_co2_val, + &gatt_co2_val, + &gatt_co2val_len); + return rc; + } else if (ctxt->op == BLE_GATT_ACCESS_OP_READ_CHR) { + rc = os_mbuf_append(ctxt->om, &gatt_co2_val, + sizeof gatt_co2_val); + return rc == 0 ? 0 : BLE_ATT_ERR_INSUFFICIENT_RES; + } + + default: + assert(0); + return BLE_ATT_ERR_UNLIKELY; + } +} +``` + +Now it's time to go into our `apps/air_quality/src/main.c` and change how we read CO2 readings and +respond to requests. + +We'll need a task handler, etc. for the co2 readings -- they were handled by the shell task but +now they need to be handled separately. + +```c +/* CO2 Task settings */ +#define CO2_TASK_PRIO 5 +#define CO2_STACK_SIZE (OS_STACK_ALIGN(336)) +struct os_eventq co2_evq; +struct os_task co2_task; +bssnz_t os_stack_t co2_stack[CO2_STACK_SIZE]; +``` + +And of course we'll need to go to our `main()` and do all the standard task and event setup we +normally do by adding this: + +```c +/* Initialize sensor eventq */ +os_eventq_init(&co2_evq); + +/* Create the CO2 reader task. + * All sensor reading operations are performed in this task. + */ +os_task_init(&co2_task, "sensor", co2_task_handler, + NULL, CO2_TASK_PRIO, OS_WAIT_FOREVER, + co2_stack, CO2_STACK_SIZE); + +``` + +We'll also need to add a task handler -- since we initialized it above: + +```c +/** + * Event loop for the sensor task. + */ +static void +co2_task_handler(void *unused) +{ + while (1) { + co2_read_event(); + /* Wait 2 second */ + os_time_delay(OS_TICKS_PER_SEC * 2); + + } +} +``` + +And finally, we'll take care of that `co2_read_event()` function: + +```c +int +co2_read_event(void) +{ + int value; + enum senseair_read_type type = SENSEAIR_CO2; + uint16_t chr_val_handle; + int rc; + + value = senseair_read(type); + if (value >= 0) { + console_printf("Got %d\n", value); + } else { + console_printf("Error while reading: %d\n", value); + goto err; + } + gatt_co2_val = value; + rc = ble_gatts_find_chr(gatt_svr_svc_co2_uuid, BLE_UUID16(CO2_SNS_VAL), NULL, &chr_val_handle); + assert(rc == 0); + ble_gatts_chr_updated(chr_val_handle); + return (0); +err: + return (rc); +} +``` + +You'll notice that it looks eeirily similar to a portion of the shell event we created +earlier. This one just reads and updates the CO2 value and sends that over BLE to any +connected clients. + +We can now build, create-image and load the app onto our Arduino Primo board, and then +connect and see the updated values! + + + +Congratulations!! + + http://git-wip-us.apache.org/repos/asf/incubator-mynewt-site/blob/443e26ac/docs/os/tutorials/pics/MyNewtSensorReader.jpg ---------------------------------------------------------------------- diff --git a/docs/os/tutorials/pics/MyNewtSensorReader.jpg b/docs/os/tutorials/pics/MyNewtSensorReader.jpg new file mode 100644 index 0000000..997a359 Binary files /dev/null and b/docs/os/tutorials/pics/MyNewtSensorReader.jpg differ http://git-wip-us.apache.org/repos/asf/incubator-mynewt-site/blob/443e26ac/mkdocs.yml ---------------------------------------------------------------------- diff --git a/mkdocs.yml b/mkdocs.yml index f185829..c1d7f1e 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -45,7 +45,9 @@ pages: - 'Tasks and Priority Management': 'os/tutorials/tasks_lesson.md' - 'Enable Wi-Fi on Arduino Zero': 'os/tutorials/wi-fi_on_arduino.md' - 'Write a Test Suite for a Package': 'os/tutorials/unit_test.md' - - 'Air-quality Sensor project': 'os/tutorials/air_quality_sensor.md' + - 'Air-quality Sensor project': + - 'Basic Air Quality Sensor': 'os/tutorials/air_quality_sensor.md' + - 'Bluetooth-enabled Air Quality Sensor': 'os/tutorials/air_quality_ble.md' - 'Add task to manage multiple events': 'os/tutorials/event_queue.md' - 'Project Slinky for remote comms': - 'Slinky on sim device': 'os/tutorials/project-slinky.md'
