andrzej-kaczmarek commented on code in PR #1476: URL: https://github.com/apache/mynewt-nimble/pull/1476#discussion_r1130921664
########## apps/lvgl_scanner/src/main.c: ########## @@ -0,0 +1,302 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#include "sysinit/sysinit.h" +#include "os/os.h" +#include "console/console.h" +#include "host/ble_hs.h" +#include "log/log.h" +#include "lvgl.h" + +#define MAX_ENTRIES 30 +#define ENTRY_ID_NONE (MAX_ENTRIES + 1) + +lv_obj_t *entries_list; + +struct list_entry_data { + int8_t last_rssi; + uint8_t addr_val[6]; +} entry_data[MAX_ENTRIES]; Review Comment: separate struct definition and variable definition, also make variable static ``` struct device_data { // ... }; static struct device_data devices[...]; ``` ########## apps/lvgl_scanner/src/main.c: ########## @@ -0,0 +1,302 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#include "sysinit/sysinit.h" +#include "os/os.h" +#include "console/console.h" +#include "host/ble_hs.h" +#include "log/log.h" +#include "lvgl.h" + +#define MAX_ENTRIES 30 +#define ENTRY_ID_NONE (MAX_ENTRIES + 1) + +lv_obj_t *entries_list; + +struct list_entry_data { + int8_t last_rssi; + uint8_t addr_val[6]; +} entry_data[MAX_ENTRIES]; + +static void +sort_entries(void) +{ + lv_obj_t *entry; + int8_t rssi1; + int8_t rssi2; + uint8_t i; + uint8_t j; + uint8_t n = lv_obj_get_child_cnt(entries_list); + + for (i = 0; i < n - 1; i++) { + for (j = 0; j < n - i - 1; j++) { + rssi1 = entry_data[j].last_rssi; + rssi2 = entry_data[j + 1].last_rssi; + + entry = lv_obj_get_child(entries_list, j + 1); + if (rssi1 < rssi2) { + struct list_entry_data help = entry_data[j + 1]; + entry_data[j + 1] = entry_data[j]; + entry_data[j] = help; + lv_obj_move_to_index(entry, j); + } + } + } +} + +static int8_t +get_entry_id_by_addr(uint8_t *addr) +{ + uint8_t n = lv_obj_get_child_cnt(entries_list); + + assert (n <= MAX_ENTRIES); + + for (uint8_t id = 0; id < n; id++) { + if (!memcmp(addr, entry_data[id].addr_val, 6)) { + return id; + } + } + return ENTRY_ID_NONE; +} + +/* This fills entry labels which are going to be displayed. Takes is_new flag as argument. + * If flag is set, then new labels will be created, otherwise existing labels will + * be updated */ +static void +fill_entry_labels(lv_obj_t *entry, struct ble_gap_ext_disc_desc *desc, uint8_t is_new) +{ + lv_obj_t *label; + + if (is_new) { + label = lv_label_create(entry); + + lv_label_set_text_fmt(label, "%02x:%02x:%02x:%02x:%02x:%02x", desc->addr.val[5], + desc->addr.val[4], desc->addr.val[3], desc->addr.val[2], + desc->addr.val[1], desc->addr.val[0]); + + label = lv_label_create(entry); + lv_label_set_text_fmt(label, "%d dB", desc->rssi); + lv_obj_align(label, LV_ALIGN_TOP_RIGHT, 0, 0); + label = lv_label_create(entry); + lv_obj_align(label, LV_ALIGN_BOTTOM_RIGHT, 0, 0); + lv_obj_set_size(entry, LV_PCT(100), 60); + } else { + label = lv_obj_get_child(entry, 1); + lv_label_set_text_fmt(label, "%d dB", desc->rssi); + label = lv_obj_get_child(entry, 2); + } + + lv_label_set_text_fmt(label, "%s", desc->prim_phy == BLE_HCI_LE_PHY_1M ? "1M" : "Coded"); + switch (desc->sec_phy) { + case BLE_HCI_LE_PHY_1M: + lv_label_ins_text(label, LV_LABEL_POS_LAST, "/1M"); + break; + case BLE_HCI_LE_PHY_2M: + lv_label_ins_text(label, LV_LABEL_POS_LAST, "/2M"); + break; + case BLE_HCI_LE_PHY_CODED: + lv_label_ins_text(label, LV_LABEL_POS_LAST, "/Coded"); + break; + default: + break; + } + + /* TODO: Add name label */ +} + +static void +add_new_entry(struct ble_gap_ext_disc_desc *desc) +{ + uint8_t id; + + lv_obj_t *entry = lv_obj_create(entries_list); + + fill_entry_labels(entry, desc, 1); + + id = lv_obj_get_child_cnt(entries_list) - 1; + entry_data[id].last_rssi = desc->rssi; + memcpy(entry_data[id].addr_val, desc->addr.val, 6); +} + +static void +update_entry(struct ble_gap_ext_disc_desc *desc, uint8_t id) +{ + uint8_t rssi_change; + lv_obj_t *entry = lv_obj_get_child(entries_list, id); + + fill_entry_labels(entry, desc, 0); + + /* Sort the list if and update RSSI if it changed significantly */ + rssi_change = abs(entry_data[id].last_rssi - desc->rssi); + if (rssi_change > 5) { + entry_data[id].last_rssi = desc->rssi; + sort_entries(); + } +} + +static uint8_t +is_event_connectable(struct ble_gap_ext_disc_desc *desc) +{ + return desc->props & BLE_HCI_ADV_CONN_MASK; +} + +static void +handle_disc_report(struct ble_gap_ext_disc_desc *desc) +{ + uint8_t id; + + /* TODO: Decide what to do with >=MAX_ENTRIES entries (list reset vs overwriting last entry) */ + if (desc->rssi < -70 || lv_obj_get_child_cnt(entries_list) >= MAX_ENTRIES) { + return; + } + + /* Filter out non-connectable advertising events */ + if (!is_event_connectable(desc)) { + return; + } + + id = get_entry_id_by_addr(desc->addr.val); + + if (id == ENTRY_ID_NONE) { + add_new_entry(desc); + sort_entries(); + } else { + update_entry(desc, id); + } +} + +static int +scan_event(struct ble_gap_event *event, void *arg) +{ + switch (event->type) { + /* advertising report has been received during discovery procedure */ + case BLE_GAP_EVENT_EXT_DISC: + handle_disc_report(&event->ext_disc); + return 0; + + default: + MODLOG_DFLT(ERROR, "Discovery event not handled\n"); + return 0; + } +} + +static void +start_scan(void) +{ + struct ble_gap_ext_disc_params coded; + struct ble_gap_ext_disc_params uncoded; + uint8_t filter_duplicates = 0; + uint8_t filter_policy = 0; + uint8_t limited = 0; + coded.passive = 1; + coded.itvl = 500; + coded.window = 250; + uncoded.passive = 1; + uncoded.itvl = 500; + uncoded.window = 250; + + ble_gap_ext_disc(BLE_OWN_ADDR_RANDOM, 0, 0, filter_duplicates, filter_policy, + limited, &uncoded, &coded, scan_event, NULL); +} + +static void +ble_app_set_addr(void) +{ + ble_addr_t addr; + int rc; + + /* Generate new non-resolvable private address */ + rc = ble_hs_id_gen_rnd(1, &addr); + assert(rc == 0); + + /* Set generated address */ + rc = ble_hs_id_set_rnd(addr.val); + assert(rc == 0); +} + +static void +on_sync(void) +{ + ble_app_set_addr(); +} + +static void +on_reset(int reason) +{ + console_printf("Resetting state; reason=%d\n", reason); +} + +static void +btn_event_cb(lv_event_t *e) +{ + static uint8_t scanning = 0; + lv_event_code_t code = lv_event_get_code(e); + lv_obj_t * btn = lv_event_get_target(e); Review Comment: `lv_obj_t *btn` ########## apps/lvgl_scanner/src/main.c: ########## @@ -0,0 +1,302 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#include "sysinit/sysinit.h" +#include "os/os.h" +#include "console/console.h" +#include "host/ble_hs.h" +#include "log/log.h" +#include "lvgl.h" + +#define MAX_ENTRIES 30 +#define ENTRY_ID_NONE (MAX_ENTRIES + 1) + +lv_obj_t *entries_list; + +struct list_entry_data { + int8_t last_rssi; + uint8_t addr_val[6]; +} entry_data[MAX_ENTRIES]; + +static void +sort_entries(void) +{ + lv_obj_t *entry; + int8_t rssi1; + int8_t rssi2; + uint8_t i; + uint8_t j; + uint8_t n = lv_obj_get_child_cnt(entries_list); + + for (i = 0; i < n - 1; i++) { + for (j = 0; j < n - i - 1; j++) { + rssi1 = entry_data[j].last_rssi; + rssi2 = entry_data[j + 1].last_rssi; + + entry = lv_obj_get_child(entries_list, j + 1); + if (rssi1 < rssi2) { + struct list_entry_data help = entry_data[j + 1]; Review Comment: local variable ########## apps/lvgl_scanner/src/main.c: ########## @@ -0,0 +1,302 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#include "sysinit/sysinit.h" +#include "os/os.h" +#include "console/console.h" +#include "host/ble_hs.h" +#include "log/log.h" +#include "lvgl.h" + +#define MAX_ENTRIES 30 +#define ENTRY_ID_NONE (MAX_ENTRIES + 1) + +lv_obj_t *entries_list; + +struct list_entry_data { + int8_t last_rssi; + uint8_t addr_val[6]; +} entry_data[MAX_ENTRIES]; + +static void +sort_entries(void) +{ + lv_obj_t *entry; + int8_t rssi1; + int8_t rssi2; + uint8_t i; + uint8_t j; + uint8_t n = lv_obj_get_child_cnt(entries_list); + + for (i = 0; i < n - 1; i++) { + for (j = 0; j < n - i - 1; j++) { Review Comment: use `qsort()` ########## apps/lvgl_scanner/src/main.c: ########## @@ -0,0 +1,302 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#include "sysinit/sysinit.h" +#include "os/os.h" +#include "console/console.h" +#include "host/ble_hs.h" +#include "log/log.h" +#include "lvgl.h" + +#define MAX_ENTRIES 30 +#define ENTRY_ID_NONE (MAX_ENTRIES + 1) + +lv_obj_t *entries_list; + +struct list_entry_data { + int8_t last_rssi; + uint8_t addr_val[6]; +} entry_data[MAX_ENTRIES]; + +static void +sort_entries(void) +{ + lv_obj_t *entry; + int8_t rssi1; + int8_t rssi2; + uint8_t i; + uint8_t j; + uint8_t n = lv_obj_get_child_cnt(entries_list); + + for (i = 0; i < n - 1; i++) { + for (j = 0; j < n - i - 1; j++) { + rssi1 = entry_data[j].last_rssi; + rssi2 = entry_data[j + 1].last_rssi; + + entry = lv_obj_get_child(entries_list, j + 1); + if (rssi1 < rssi2) { + struct list_entry_data help = entry_data[j + 1]; + entry_data[j + 1] = entry_data[j]; + entry_data[j] = help; + lv_obj_move_to_index(entry, j); + } + } + } +} + +static int8_t +get_entry_id_by_addr(uint8_t *addr) +{ + uint8_t n = lv_obj_get_child_cnt(entries_list); + + assert (n <= MAX_ENTRIES); + + for (uint8_t id = 0; id < n; id++) { + if (!memcmp(addr, entry_data[id].addr_val, 6)) { + return id; + } + } + return ENTRY_ID_NONE; +} + +/* This fills entry labels which are going to be displayed. Takes is_new flag as argument. + * If flag is set, then new labels will be created, otherwise existing labels will + * be updated */ +static void +fill_entry_labels(lv_obj_t *entry, struct ble_gap_ext_disc_desc *desc, uint8_t is_new) +{ + lv_obj_t *label; + + if (is_new) { + label = lv_label_create(entry); + + lv_label_set_text_fmt(label, "%02x:%02x:%02x:%02x:%02x:%02x", desc->addr.val[5], + desc->addr.val[4], desc->addr.val[3], desc->addr.val[2], + desc->addr.val[1], desc->addr.val[0]); + + label = lv_label_create(entry); + lv_label_set_text_fmt(label, "%d dB", desc->rssi); + lv_obj_align(label, LV_ALIGN_TOP_RIGHT, 0, 0); + label = lv_label_create(entry); + lv_obj_align(label, LV_ALIGN_BOTTOM_RIGHT, 0, 0); + lv_obj_set_size(entry, LV_PCT(100), 60); + } else { + label = lv_obj_get_child(entry, 1); + lv_label_set_text_fmt(label, "%d dB", desc->rssi); + label = lv_obj_get_child(entry, 2); + } + + lv_label_set_text_fmt(label, "%s", desc->prim_phy == BLE_HCI_LE_PHY_1M ? "1M" : "Coded"); + switch (desc->sec_phy) { + case BLE_HCI_LE_PHY_1M: + lv_label_ins_text(label, LV_LABEL_POS_LAST, "/1M"); + break; + case BLE_HCI_LE_PHY_2M: + lv_label_ins_text(label, LV_LABEL_POS_LAST, "/2M"); + break; + case BLE_HCI_LE_PHY_CODED: + lv_label_ins_text(label, LV_LABEL_POS_LAST, "/Coded"); + break; + default: + break; + } + + /* TODO: Add name label */ +} + +static void +add_new_entry(struct ble_gap_ext_disc_desc *desc) +{ + uint8_t id; + + lv_obj_t *entry = lv_obj_create(entries_list); + + fill_entry_labels(entry, desc, 1); + + id = lv_obj_get_child_cnt(entries_list) - 1; + entry_data[id].last_rssi = desc->rssi; + memcpy(entry_data[id].addr_val, desc->addr.val, 6); +} + +static void +update_entry(struct ble_gap_ext_disc_desc *desc, uint8_t id) +{ + uint8_t rssi_change; + lv_obj_t *entry = lv_obj_get_child(entries_list, id); + + fill_entry_labels(entry, desc, 0); + + /* Sort the list if and update RSSI if it changed significantly */ + rssi_change = abs(entry_data[id].last_rssi - desc->rssi); + if (rssi_change > 5) { + entry_data[id].last_rssi = desc->rssi; + sort_entries(); + } +} + +static uint8_t +is_event_connectable(struct ble_gap_ext_disc_desc *desc) +{ + return desc->props & BLE_HCI_ADV_CONN_MASK; +} + +static void +handle_disc_report(struct ble_gap_ext_disc_desc *desc) +{ + uint8_t id; + + /* TODO: Decide what to do with >=MAX_ENTRIES entries (list reset vs overwriting last entry) */ + if (desc->rssi < -70 || lv_obj_get_child_cnt(entries_list) >= MAX_ENTRIES) { + return; + } + + /* Filter out non-connectable advertising events */ + if (!is_event_connectable(desc)) { + return; + } + + id = get_entry_id_by_addr(desc->addr.val); + + if (id == ENTRY_ID_NONE) { + add_new_entry(desc); + sort_entries(); + } else { + update_entry(desc, id); + } +} + +static int +scan_event(struct ble_gap_event *event, void *arg) +{ + switch (event->type) { + /* advertising report has been received during discovery procedure */ + case BLE_GAP_EVENT_EXT_DISC: + handle_disc_report(&event->ext_disc); + return 0; + + default: + MODLOG_DFLT(ERROR, "Discovery event not handled\n"); + return 0; + } +} + +static void +start_scan(void) +{ + struct ble_gap_ext_disc_params coded; + struct ble_gap_ext_disc_params uncoded; + uint8_t filter_duplicates = 0; + uint8_t filter_policy = 0; + uint8_t limited = 0; + coded.passive = 1; + coded.itvl = 500; Review Comment: use `BLE_GAP_SCAN_ITVL_MS` and `BLE_GAP_SCAN_WIN_MS` macros and configure for 100% duty cycle ########## apps/lvgl_scanner/src/main.c: ########## @@ -0,0 +1,302 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#include "sysinit/sysinit.h" +#include "os/os.h" +#include "console/console.h" +#include "host/ble_hs.h" +#include "log/log.h" +#include "lvgl.h" + +#define MAX_ENTRIES 30 +#define ENTRY_ID_NONE (MAX_ENTRIES + 1) + +lv_obj_t *entries_list; + +struct list_entry_data { + int8_t last_rssi; + uint8_t addr_val[6]; +} entry_data[MAX_ENTRIES]; + +static void +sort_entries(void) +{ + lv_obj_t *entry; + int8_t rssi1; + int8_t rssi2; + uint8_t i; + uint8_t j; + uint8_t n = lv_obj_get_child_cnt(entries_list); + + for (i = 0; i < n - 1; i++) { + for (j = 0; j < n - i - 1; j++) { + rssi1 = entry_data[j].last_rssi; + rssi2 = entry_data[j + 1].last_rssi; + + entry = lv_obj_get_child(entries_list, j + 1); + if (rssi1 < rssi2) { + struct list_entry_data help = entry_data[j + 1]; + entry_data[j + 1] = entry_data[j]; + entry_data[j] = help; + lv_obj_move_to_index(entry, j); + } + } + } +} + +static int8_t +get_entry_id_by_addr(uint8_t *addr) +{ + uint8_t n = lv_obj_get_child_cnt(entries_list); + + assert (n <= MAX_ENTRIES); + + for (uint8_t id = 0; id < n; id++) { Review Comment: `id` should be a local variable ########## apps/lvgl_scanner/src/main.c: ########## @@ -0,0 +1,302 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#include "sysinit/sysinit.h" +#include "os/os.h" +#include "console/console.h" +#include "host/ble_hs.h" +#include "log/log.h" +#include "lvgl.h" + +#define MAX_ENTRIES 30 +#define ENTRY_ID_NONE (MAX_ENTRIES + 1) + +lv_obj_t *entries_list; + +struct list_entry_data { + int8_t last_rssi; + uint8_t addr_val[6]; +} entry_data[MAX_ENTRIES]; + +static void +sort_entries(void) +{ + lv_obj_t *entry; + int8_t rssi1; + int8_t rssi2; + uint8_t i; + uint8_t j; + uint8_t n = lv_obj_get_child_cnt(entries_list); + + for (i = 0; i < n - 1; i++) { + for (j = 0; j < n - i - 1; j++) { + rssi1 = entry_data[j].last_rssi; + rssi2 = entry_data[j + 1].last_rssi; + + entry = lv_obj_get_child(entries_list, j + 1); + if (rssi1 < rssi2) { + struct list_entry_data help = entry_data[j + 1]; + entry_data[j + 1] = entry_data[j]; + entry_data[j] = help; + lv_obj_move_to_index(entry, j); + } + } + } +} + +static int8_t +get_entry_id_by_addr(uint8_t *addr) +{ + uint8_t n = lv_obj_get_child_cnt(entries_list); + + assert (n <= MAX_ENTRIES); + + for (uint8_t id = 0; id < n; id++) { + if (!memcmp(addr, entry_data[id].addr_val, 6)) { + return id; + } + } + return ENTRY_ID_NONE; +} + +/* This fills entry labels which are going to be displayed. Takes is_new flag as argument. + * If flag is set, then new labels will be created, otherwise existing labels will + * be updated */ +static void +fill_entry_labels(lv_obj_t *entry, struct ble_gap_ext_disc_desc *desc, uint8_t is_new) +{ + lv_obj_t *label; + + if (is_new) { + label = lv_label_create(entry); + + lv_label_set_text_fmt(label, "%02x:%02x:%02x:%02x:%02x:%02x", desc->addr.val[5], + desc->addr.val[4], desc->addr.val[3], desc->addr.val[2], + desc->addr.val[1], desc->addr.val[0]); + + label = lv_label_create(entry); + lv_label_set_text_fmt(label, "%d dB", desc->rssi); + lv_obj_align(label, LV_ALIGN_TOP_RIGHT, 0, 0); + label = lv_label_create(entry); + lv_obj_align(label, LV_ALIGN_BOTTOM_RIGHT, 0, 0); + lv_obj_set_size(entry, LV_PCT(100), 60); + } else { + label = lv_obj_get_child(entry, 1); + lv_label_set_text_fmt(label, "%d dB", desc->rssi); + label = lv_obj_get_child(entry, 2); + } + + lv_label_set_text_fmt(label, "%s", desc->prim_phy == BLE_HCI_LE_PHY_1M ? "1M" : "Coded"); + switch (desc->sec_phy) { + case BLE_HCI_LE_PHY_1M: + lv_label_ins_text(label, LV_LABEL_POS_LAST, "/1M"); + break; + case BLE_HCI_LE_PHY_2M: + lv_label_ins_text(label, LV_LABEL_POS_LAST, "/2M"); + break; + case BLE_HCI_LE_PHY_CODED: + lv_label_ins_text(label, LV_LABEL_POS_LAST, "/Coded"); + break; + default: + break; + } + + /* TODO: Add name label */ +} + +static void +add_new_entry(struct ble_gap_ext_disc_desc *desc) +{ + uint8_t id; + + lv_obj_t *entry = lv_obj_create(entries_list); + + fill_entry_labels(entry, desc, 1); + + id = lv_obj_get_child_cnt(entries_list) - 1; + entry_data[id].last_rssi = desc->rssi; + memcpy(entry_data[id].addr_val, desc->addr.val, 6); +} + +static void +update_entry(struct ble_gap_ext_disc_desc *desc, uint8_t id) +{ + uint8_t rssi_change; + lv_obj_t *entry = lv_obj_get_child(entries_list, id); + + fill_entry_labels(entry, desc, 0); + + /* Sort the list if and update RSSI if it changed significantly */ + rssi_change = abs(entry_data[id].last_rssi - desc->rssi); + if (rssi_change > 5) { + entry_data[id].last_rssi = desc->rssi; + sort_entries(); + } +} + +static uint8_t +is_event_connectable(struct ble_gap_ext_disc_desc *desc) +{ + return desc->props & BLE_HCI_ADV_CONN_MASK; +} + +static void +handle_disc_report(struct ble_gap_ext_disc_desc *desc) +{ + uint8_t id; + + /* TODO: Decide what to do with >=MAX_ENTRIES entries (list reset vs overwriting last entry) */ + if (desc->rssi < -70 || lv_obj_get_child_cnt(entries_list) >= MAX_ENTRIES) { + return; + } + + /* Filter out non-connectable advertising events */ + if (!is_event_connectable(desc)) { + return; + } + + id = get_entry_id_by_addr(desc->addr.val); + + if (id == ENTRY_ID_NONE) { + add_new_entry(desc); + sort_entries(); + } else { + update_entry(desc, id); + } +} + +static int +scan_event(struct ble_gap_event *event, void *arg) +{ + switch (event->type) { + /* advertising report has been received during discovery procedure */ + case BLE_GAP_EVENT_EXT_DISC: + handle_disc_report(&event->ext_disc); + return 0; + + default: + MODLOG_DFLT(ERROR, "Discovery event not handled\n"); + return 0; + } +} + +static void +start_scan(void) +{ + struct ble_gap_ext_disc_params coded; + struct ble_gap_ext_disc_params uncoded; + uint8_t filter_duplicates = 0; + uint8_t filter_policy = 0; + uint8_t limited = 0; + coded.passive = 1; Review Comment: use active scanning, some devices may have local name in scan_rsp only ########## apps/lvgl_scanner/src/main.c: ########## @@ -0,0 +1,302 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#include "sysinit/sysinit.h" +#include "os/os.h" +#include "console/console.h" +#include "host/ble_hs.h" +#include "log/log.h" +#include "lvgl.h" + +#define MAX_ENTRIES 30 +#define ENTRY_ID_NONE (MAX_ENTRIES + 1) + +lv_obj_t *entries_list; + +struct list_entry_data { + int8_t last_rssi; + uint8_t addr_val[6]; Review Comment: `ble_addr_t` ########## apps/lvgl_scanner/src/main.c: ########## @@ -0,0 +1,302 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#include "sysinit/sysinit.h" +#include "os/os.h" +#include "console/console.h" +#include "host/ble_hs.h" +#include "log/log.h" +#include "lvgl.h" + +#define MAX_ENTRIES 30 +#define ENTRY_ID_NONE (MAX_ENTRIES + 1) + +lv_obj_t *entries_list; + +struct list_entry_data { + int8_t last_rssi; + uint8_t addr_val[6]; +} entry_data[MAX_ENTRIES]; + +static void +sort_entries(void) +{ + lv_obj_t *entry; + int8_t rssi1; + int8_t rssi2; + uint8_t i; + uint8_t j; + uint8_t n = lv_obj_get_child_cnt(entries_list); + + for (i = 0; i < n - 1; i++) { + for (j = 0; j < n - i - 1; j++) { + rssi1 = entry_data[j].last_rssi; + rssi2 = entry_data[j + 1].last_rssi; + + entry = lv_obj_get_child(entries_list, j + 1); Review Comment: this can be called inside if below ########## apps/lvgl_scanner/src/main.c: ########## @@ -0,0 +1,302 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#include "sysinit/sysinit.h" +#include "os/os.h" +#include "console/console.h" +#include "host/ble_hs.h" +#include "log/log.h" +#include "lvgl.h" + +#define MAX_ENTRIES 30 +#define ENTRY_ID_NONE (MAX_ENTRIES + 1) + +lv_obj_t *entries_list; + +struct list_entry_data { + int8_t last_rssi; + uint8_t addr_val[6]; +} entry_data[MAX_ENTRIES]; + +static void +sort_entries(void) +{ + lv_obj_t *entry; + int8_t rssi1; + int8_t rssi2; + uint8_t i; + uint8_t j; + uint8_t n = lv_obj_get_child_cnt(entries_list); + + for (i = 0; i < n - 1; i++) { + for (j = 0; j < n - i - 1; j++) { + rssi1 = entry_data[j].last_rssi; + rssi2 = entry_data[j + 1].last_rssi; + + entry = lv_obj_get_child(entries_list, j + 1); + if (rssi1 < rssi2) { + struct list_entry_data help = entry_data[j + 1]; + entry_data[j + 1] = entry_data[j]; + entry_data[j] = help; + lv_obj_move_to_index(entry, j); + } + } + } +} + +static int8_t +get_entry_id_by_addr(uint8_t *addr) +{ + uint8_t n = lv_obj_get_child_cnt(entries_list); + + assert (n <= MAX_ENTRIES); + + for (uint8_t id = 0; id < n; id++) { + if (!memcmp(addr, entry_data[id].addr_val, 6)) { + return id; + } + } + return ENTRY_ID_NONE; Review Comment: better use `int` as return value type and simply return -1 ########## apps/lvgl_scanner/src/main.c: ########## @@ -0,0 +1,302 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#include "sysinit/sysinit.h" +#include "os/os.h" +#include "console/console.h" +#include "host/ble_hs.h" +#include "log/log.h" +#include "lvgl.h" + +#define MAX_ENTRIES 30 +#define ENTRY_ID_NONE (MAX_ENTRIES + 1) + +lv_obj_t *entries_list; + +struct list_entry_data { + int8_t last_rssi; + uint8_t addr_val[6]; +} entry_data[MAX_ENTRIES]; + +static void +sort_entries(void) +{ + lv_obj_t *entry; + int8_t rssi1; + int8_t rssi2; + uint8_t i; + uint8_t j; + uint8_t n = lv_obj_get_child_cnt(entries_list); + + for (i = 0; i < n - 1; i++) { + for (j = 0; j < n - i - 1; j++) { + rssi1 = entry_data[j].last_rssi; + rssi2 = entry_data[j + 1].last_rssi; + + entry = lv_obj_get_child(entries_list, j + 1); + if (rssi1 < rssi2) { + struct list_entry_data help = entry_data[j + 1]; + entry_data[j + 1] = entry_data[j]; + entry_data[j] = help; + lv_obj_move_to_index(entry, j); Review Comment: you can add pointer to object to `entry_data` struct, then simply sort entries and move objects to appropriate positions after sorting is done. this way you don't need to move them multiple times during sorting -- This is an automated message from the Apache Git Service. To respond to the message, please log on to GitHub and use the URL above to go to the specific comment. To unsubscribe, e-mail: commits-unsubscr...@mynewt.apache.org For queries about this service, please contact Infrastructure at: us...@infra.apache.org