From cdbcff1a99c2fdcfc5a42020fc878212d5644b3e Mon Sep 17 00:00:00 2001 From: JF Date: Sun, 20 Sep 2020 18:42:46 +0200 Subject: [PATCH] [WIP] Add BLE HID Mouse + add mouse moves in InfiniPaint app. --- src/CMakeLists.txt | 5 +- src/Components/Ble/BleMouse.cpp | 13 +++ src/Components/Ble/BleMouse.h | 20 ++++ src/Components/Ble/HidService.cpp | 123 ++++++++++++++++++++++--- src/Components/Ble/HidService.h | 12 ++- src/Components/Ble/NimbleController.h | 2 + src/DisplayApp/DisplayApp.cpp | 6 +- src/DisplayApp/DisplayApp.h | 5 +- src/DisplayApp/Screens/InfiniPaint.cpp | 26 +++++- src/DisplayApp/Screens/InfiniPaint.h | 9 +- src/SystemTask/SystemTask.cpp | 5 +- src/SystemTask/SystemTask.h | 2 + 12 files changed, 205 insertions(+), 23 deletions(-) create mode 100644 src/Components/Ble/BleMouse.cpp create mode 100644 src/Components/Ble/BleMouse.h diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index babef89d..67e6845f 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -348,6 +348,7 @@ list(APPEND SOURCE_FILES DisplayApp/Screens/Music.cpp Components/Ble/HidService.cpp Components/Ble/BatteryInformationService.cpp + Components/Ble/BleMouse.cpp DisplayApp/Screens/FirmwareValidation.cpp DisplayApp/Screens/ApplicationList.cpp main.cpp @@ -443,7 +444,9 @@ set(INCLUDE_FILES Components/Ble/CurrentTimeClient.h Components/Ble/AlertNotificationClient.h Components/Ble/DfuService.h - Components/FirmwareValidator/FirmwareValidator.h + Components/Ble/BleMouse.h + + Components/FirmwareValidator/FirmwareValidator.h drivers/Cst816s.h FreeRTOS/portmacro.h FreeRTOS/portmacro_cmsis.h diff --git a/src/Components/Ble/BleMouse.cpp b/src/Components/Ble/BleMouse.cpp new file mode 100644 index 00000000..389d15e9 --- /dev/null +++ b/src/Components/Ble/BleMouse.cpp @@ -0,0 +1,13 @@ + +#include "BleMouse.h" +#include "HidService.h" + +using namespace Pinetime::Controllers; + +BleMouse::BleMouse(HidService& hidService) : hidService{hidService} { + +} + +void BleMouse::Move(uint8_t x, uint8_t y) { + hidService.SendMoveReport(x, y); +} diff --git a/src/Components/Ble/BleMouse.h b/src/Components/Ble/BleMouse.h new file mode 100644 index 00000000..994740f4 --- /dev/null +++ b/src/Components/Ble/BleMouse.h @@ -0,0 +1,20 @@ +#pragma once + +#include + +namespace Pinetime { + namespace Controllers { + class HidService; + class BleMouse { + public: + explicit BleMouse(HidService& hidService); + + void Move(uint8_t x, uint8_t y); + + private: + HidService& hidService; + }; + } +} + + diff --git a/src/Components/Ble/HidService.cpp b/src/Components/Ble/HidService.cpp index 4e0e18a7..d7014e5a 100644 --- a/src/Components/Ble/HidService.cpp +++ b/src/Components/Ble/HidService.cpp @@ -37,6 +37,11 @@ namespace { return hidService->OnReportDescriptorRequested(conn_handle, attr_handle, ctxt); } + int HidServiceReportMouseDescriptorCallback(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt *ctxt, void *arg) { + auto* hidService = static_cast(arg); + return hidService->OnReportDescriptorMouseRequested(conn_handle, attr_handle, ctxt); + } + int HidServiceReportMapDescriptorCallback(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt *ctxt, void *arg) { auto* hidService = static_cast(arg); @@ -90,6 +95,35 @@ namespace { 0x81, 0x00, // Input: (Data, Array) // 0xC0, // End Collection + + + + 0x05, 0x01, // USAGE_PAGE (Generic Desktop) 0 + 0x09, 0x02, // USAGE (Mouse) 2 + 0xa1, 0x01, // COLLECTION (Application) 4 + 0x85, 0x02, // REPORT_ID (Mouse) 6 + 0x09, 0x01, // USAGE (Pointer) 8 + 0xa1, 0x00, // COLLECTION (Physical) 10 + 0x05, 0x09, // USAGE_PAGE (Button) 12 + 0x19, 0x01, // USAGE_MINIMUM (Button 1) 14 + 0x29, 0x02, // USAGE_MAXIMUM (Button 2) 16 + 0x15, 0x00, // LOGICAL_MINIMUM (0) 18 + 0x25, 0x01, // LOGICAL_MAXIMUM (1) 20 + 0x75, 0x01, // REPORT_SIZE (1) 22 + 0x95, 0x02, // REPORT_COUNT (2) 24 + 0x81, 0x02, // INPUT (Data,Var,Abs) 26 + 0x95, 0x06, // REPORT_COUNT (6) 28 + 0x81, 0x03, // INPUT (Cnst,Var,Abs) 30 + 0x05, 0x01, // USAGE_PAGE (Generic Desktop) 32 + 0x09, 0x30, // USAGE (X) 34 + 0x09, 0x31, // USAGE (Y) 36 + 0x15, 0x81, // LOGICAL_MINIMUM (-127) 38 + 0x25, 0x7f, // LOGICAL_MAXIMUM (127) 40 + 0x75, 0x08, // REPORT_SIZE (8) 42 + 0x95, 0x02, // REPORT_COUNT (2) 44 + 0x81, 0x06, // INPUT (Data,Var,Rel) 46 + 0xc0, // END_COLLECTION 48 + 0xc0 // END_COLLECTION 49/50 }; } @@ -110,11 +144,17 @@ HidService::HidService() : }, {0} }, - reportDescriptorDefinition{{ - .uuid = (const ble_uuid_t *) &descriptorUuid, - .att_flags = 5, - .access_cb = HidServiceReportDescriptorCallback, - },{0} + reportKeyboardDescriptorDefinition{{ + .uuid = (const ble_uuid_t *) &descriptorUuid, + .att_flags = 5, + .access_cb = HidServiceReportDescriptorCallback, + }, {0} + }, + reportMouseDescriptorDefinition{{ + .uuid = (const ble_uuid_t *) &descriptorUuid, + .att_flags = 5, + .access_cb = HidServiceReportMouseDescriptorCallback, + }, {0} }, reportMapDescriptorDefinitions{ { @@ -136,9 +176,17 @@ HidService::HidService() : .uuid = (ble_uuid_t *) &reportUuid, .access_cb = HidServiceCallback, .arg = this, - .descriptors = reportDescriptorDefinition, + .descriptors = reportKeyboardDescriptorDefinition, .flags = BLE_GATT_CHR_F_READ | BLE_GATT_CHR_F_NOTIFY | BLE_GATT_CHR_F_WRITE, - .val_handle = &reportHandle + .val_handle = &reportKeyboardHandle + }, + { + .uuid = (ble_uuid_t *) &reportUuid, + .access_cb = HidServiceCallback, + .arg = this, + .descriptors = reportMouseDescriptorDefinition, + .flags = BLE_GATT_CHR_F_READ | BLE_GATT_CHR_F_NOTIFY | BLE_GATT_CHR_F_WRITE, + .val_handle = &reportMouseHandle }, { .uuid = (ble_uuid_t *) &reportMapUuid, @@ -220,7 +268,7 @@ HidService::OnHidServiceRequested(uint16_t connectionHandle, uint16_t attributeH attribute = "protocolModeHandle"; static uint8_t protcoleModeValue = 1; res = os_mbuf_append(context->om, &protcoleModeValue, 1); - } else if(attributeHandle == reportHandle) { + } else if(attributeHandle == reportKeyboardHandle) { attribute = "reportHandle"; } else if(attributeHandle == reportMapHandle) { attribute = "reportMapHandle"; @@ -253,6 +301,16 @@ int HidService::OnReportDescriptorRequested(uint16_t connectionHandle, uint16_t return res; } +int HidService::OnReportDescriptorMouseRequested(uint16_t connectionHandle, uint16_t attributeHandle, + ble_gatt_access_ctxt *context) { + NRF_LOG_INFO("HID : Attribute = %d = Callback report descriptor Mouse, operation = %s",attributeHandle, ::OperationToString(context->op)); + int res = 0; + static uint16_t reportValue = 0x0102; + + res = os_mbuf_append(context->om, &reportValue, 2); + return res; +} + int HidService::OnReportMapDescriptorRequested(uint16_t connectionHandle, uint16_t attributeHandle, ble_gatt_access_ctxt *context) { NRF_LOG_INFO("HID : Attribute = %d = Callback report map descriptor, operation = %s",attributeHandle, ::OperationToString(context->op)); @@ -280,7 +338,7 @@ uint8_t helloWorld[] { uint8_t testIndex = 0; bool push = true; void HidService::Test() { -# if 1 +# if 0 uint8_t modif = (testIndex == 0) ? (1<<1) : 0; if(push && testIndex < 12) { uint8_t buf[9]{modif, 0x0, 0x00, helloWorld[testIndex], 0x00, 0x00, 0x00, 0x00, 0x00}; @@ -291,7 +349,7 @@ void HidService::Test() { if (connectionHandle == 0 || connectionHandle == BLE_HS_CONN_HANDLE_NONE) { return; } - ble_gattc_notify_custom(1, reportHandle, om); + ble_gattc_notify_custom(1, reportKeyboardHandle, om); testIndex++; push = false; NRF_LOG_INFO("PUSH %d %d", helloWorld[testIndex], modif); @@ -304,12 +362,55 @@ void HidService::Test() { if (connectionHandle == 0 || connectionHandle == BLE_HS_CONN_HANDLE_NONE) { return; } - ble_gattc_notify_custom(1, reportHandle, om); + ble_gattc_notify_custom(1, reportKeyboardHandle, om); NRF_LOG_INFO("Release"); push = true; } #endif + +#if 0 + if(testIndex%2 == 0) { + uint8_t buf[3]{0, 2, 0}; + auto *om = ble_hs_mbuf_from_flat(&buf, 3); + + uint16_t connectionHandle = 1; + + if (connectionHandle == 0 || connectionHandle == BLE_HS_CONN_HANDLE_NONE) { + return; + } + ble_gattc_notify_custom(1, reportMouseHandle, om); + testIndex++; + push = false; + NRF_LOG_INFO("UNPUSH"); + } else { + uint8_t buf[3]{0, 0, 2}; + auto *om = ble_hs_mbuf_from_flat(&buf, 3); + + uint16_t connectionHandle = 1; + + if (connectionHandle == 0 || connectionHandle == BLE_HS_CONN_HANDLE_NONE) { + return; + } + ble_gattc_notify_custom(1, reportMouseHandle, om); + testIndex++; + push = false; + NRF_LOG_INFO("PUSH"); + } +#endif +} + +void HidService::SendMoveReport(uint8_t x, uint8_t y) { + uint8_t buf[3]{0, x, y}; + auto *om = ble_hs_mbuf_from_flat(&buf, 3); + + uint16_t connectionHandle = 1; + + if (connectionHandle == 0 || connectionHandle == BLE_HS_CONN_HANDLE_NONE) { + return; + } + ble_gattc_notify_custom(1, reportMouseHandle, om); + NRF_LOG_INFO("move"); } diff --git a/src/Components/Ble/HidService.h b/src/Components/Ble/HidService.h index a9d87d1f..782dad7a 100644 --- a/src/Components/Ble/HidService.h +++ b/src/Components/Ble/HidService.h @@ -13,14 +13,16 @@ namespace Pinetime { int OnHidServiceRequested(uint16_t connectionHandle, uint16_t attributeHandle, ble_gatt_access_ctxt *context); - int - OnReportDescriptorRequested(uint16_t connectionHandle, uint16_t attributeHandle, ble_gatt_access_ctxt *context); + int OnReportDescriptorRequested(uint16_t connectionHandle, uint16_t attributeHandle, ble_gatt_access_ctxt *context); + int OnReportDescriptorMouseRequested(uint16_t connectionHandle, uint16_t attributeHandle, ble_gatt_access_ctxt *context); int OnReportMapDescriptorRequested(uint16_t connectionHandle, uint16_t attributeHandle, ble_gatt_access_ctxt *context); void Test(); + void SendMoveReport(uint8_t x, uint8_t y); + private: static constexpr uint16_t hidServiceId {0x1812}; static constexpr uint16_t protocolModeId {0x2A4E}; @@ -94,13 +96,15 @@ namespace Pinetime { struct ble_gatt_dsc_def reportInDescriptorDefinition[2]; struct ble_gatt_dsc_def reportOutDescriptorDefinition[2]; - struct ble_gatt_dsc_def reportDescriptorDefinition[2]; + struct ble_gatt_dsc_def reportKeyboardDescriptorDefinition[2]; + struct ble_gatt_dsc_def reportMouseDescriptorDefinition[2]; struct ble_gatt_dsc_def reportMapDescriptorDefinitions[2]; struct ble_gatt_chr_def characteristicDefinition[9]; struct ble_gatt_svc_def serviceDefinition[2]; uint16_t protocolModeHandle; - uint16_t reportHandle; + uint16_t reportKeyboardHandle; + uint16_t reportMouseHandle; uint16_t reportMapHandle; uint16_t informationHandle; uint16_t controlPointHandle; diff --git a/src/Components/Ble/NimbleController.h b/src/Components/Ble/NimbleController.h index 300b5f5b..dca7e0a1 100644 --- a/src/Components/Ble/NimbleController.h +++ b/src/Components/Ble/NimbleController.h @@ -46,6 +46,8 @@ namespace Pinetime { void Test(); + HidService& GetHidService() { return hidService;} + private: static constexpr const char* deviceName = "Pinetime-JF"; Pinetime::System::SystemTask& systemTask; diff --git a/src/DisplayApp/DisplayApp.cpp b/src/DisplayApp/DisplayApp.cpp index f6138ec7..1d044be0 100644 --- a/src/DisplayApp/DisplayApp.cpp +++ b/src/DisplayApp/DisplayApp.cpp @@ -26,7 +26,8 @@ DisplayApp::DisplayApp(Drivers::St7789 &lcd, Components::LittleVgl &lvgl, Driver Controllers::Battery &batteryController, Controllers::Ble &bleController, Controllers::DateTime &dateTimeController, Drivers::WatchdogView &watchdog, System::SystemTask &systemTask, - Pinetime::Controllers::NotificationManager& notificationManager) : + Pinetime::Controllers::NotificationManager& notificationManager, + Controllers::BleMouse& bleMouse) : lcd{lcd}, lvgl{lvgl}, batteryController{batteryController}, @@ -34,6 +35,7 @@ DisplayApp::DisplayApp(Drivers::St7789 &lcd, Components::LittleVgl &lvgl, Driver dateTimeController{dateTimeController}, watchdog{watchdog}, touchPanel{touchPanel}, + bleMouse{bleMouse}, currentScreen{new Screens::Clock(this, dateTimeController, batteryController, bleController) }, systemTask{systemTask}, notificationManager{notificationManager} { @@ -197,7 +199,7 @@ void DisplayApp::RunningState() { case Apps::SysInfo: currentScreen.reset(new Screens::SystemInfo(this, dateTimeController, batteryController, brightnessController, bleController, watchdog)); break; case Apps::Meter: currentScreen.reset(new Screens::Meter(this)); break; case Apps::Gauge: currentScreen.reset(new Screens::Gauge(this)); break; - case Apps::Paint: currentScreen.reset(new Screens::InfiniPaint(this, lvgl)); break; + case Apps::Paint: currentScreen.reset(new Screens::InfiniPaint(this, lvgl, bleMouse)); break; case Apps::Brightness : currentScreen.reset(new Screens::Brightness(this, brightnessController)); break; case Apps::Music : currentScreen.reset(new Screens::Music(this, systemTask.nimble().music())); break; case Apps::FirmwareValidation: currentScreen.reset(new Screens::FirmwareValidation(this, validator)); break; diff --git a/src/DisplayApp/DisplayApp.h b/src/DisplayApp/DisplayApp.h index 345e06d4..3c706651 100644 --- a/src/DisplayApp/DisplayApp.h +++ b/src/DisplayApp/DisplayApp.h @@ -18,6 +18,7 @@ #include #include #include +#include #include "TouchEvents.h" #include "Apps.h" @@ -40,7 +41,8 @@ namespace Pinetime { Controllers::Battery &batteryController, Controllers::Ble &bleController, Controllers::DateTime &dateTimeController, Drivers::WatchdogView &watchdog, System::SystemTask &systemTask, - Pinetime::Controllers::NotificationManager& notificationManager); + Pinetime::Controllers::NotificationManager& notificationManager, + Controllers::BleMouse& bleMouse); void Start(); void PushMessage(Messages msg); @@ -72,6 +74,7 @@ namespace Pinetime { Pinetime::Drivers::Cst816S& touchPanel; TouchEvents OnTouchEvent(); + Controllers::BleMouse& bleMouse; std::unique_ptr currentScreen; diff --git a/src/DisplayApp/Screens/InfiniPaint.cpp b/src/DisplayApp/Screens/InfiniPaint.cpp index b340f5d8..3a04373b 100644 --- a/src/DisplayApp/Screens/InfiniPaint.cpp +++ b/src/DisplayApp/Screens/InfiniPaint.cpp @@ -7,7 +7,10 @@ using namespace Pinetime::Applications::Screens; extern lv_font_t jetbrains_mono_extrabold_compressed; extern lv_font_t jetbrains_mono_bold_20; -InfiniPaint::InfiniPaint(Pinetime::Applications::DisplayApp *app, Pinetime::Components::LittleVgl& lvgl) : Screen(app), lvgl{lvgl} { +InfiniPaint::InfiniPaint(Pinetime::Applications::DisplayApp *app, + Pinetime::Components::LittleVgl& lvgl, + Controllers::BleMouse& bleMouse) : + Screen(app), lvgl{lvgl}, bleMouse{bleMouse} { app->SetTouchMode(DisplayApp::TouchModes::Polling); std::fill(b, b+bufferSize, LV_COLOR_WHITE); } @@ -19,6 +22,10 @@ InfiniPaint::~InfiniPaint() { } bool InfiniPaint::Refresh() { + timeout--; + if(timeout == 0) { + moving = false; + } return running; } @@ -28,10 +35,13 @@ bool InfiniPaint::OnButtonPushed() { } bool InfiniPaint::OnTouchEvent(Pinetime::Applications::TouchEvents event) { + NRF_LOG_INFO("TOUCH %d", event); return true; } bool InfiniPaint::OnTouchEvent(uint16_t x, uint16_t y) { + NRF_LOG_INFO("TOUCH %d, %d", x, y); + lv_area_t area; area.x1 = x-(width/2); area.y1 = y-(height/2); @@ -39,6 +49,20 @@ bool InfiniPaint::OnTouchEvent(uint16_t x, uint16_t y) { area.y2 = y+(height/2)-1; lvgl.SetFullRefresh(Components::LittleVgl::FullRefreshDirections::None); lvgl.FlushDisplay(&area, b); + + if(!moving) { + moving = true; + lastX = x; + lastY = y; + + } else { + + bleMouse.Move((x - lastX)*2, (y - lastY)*2); + lastX = x; + lastY = y; + } + timeout = 20; + return true; } diff --git a/src/DisplayApp/Screens/InfiniPaint.h b/src/DisplayApp/Screens/InfiniPaint.h index a1592f97..70a74d1b 100644 --- a/src/DisplayApp/Screens/InfiniPaint.h +++ b/src/DisplayApp/Screens/InfiniPaint.h @@ -7,6 +7,7 @@ #include #include #include +#include namespace Pinetime { namespace Applications { @@ -14,7 +15,7 @@ namespace Pinetime { class InfiniPaint : public Screen{ public: - InfiniPaint(DisplayApp* app, Pinetime::Components::LittleVgl& lvgl); + InfiniPaint(DisplayApp* app, Pinetime::Components::LittleVgl& lvgl, Controllers::BleMouse& bleMouse); ~InfiniPaint() override; bool Refresh() override; @@ -29,6 +30,12 @@ namespace Pinetime { static constexpr uint16_t bufferSize = width*height; lv_color_t b[bufferSize]; bool running = true; + Controllers::BleMouse& bleMouse; + + bool moving = false; + uint8_t lastX; + uint8_t lastY; + uint8_t timeout = 10; }; } } diff --git a/src/SystemTask/SystemTask.cpp b/src/SystemTask/SystemTask.cpp index 66d429e2..fce71d94 100644 --- a/src/SystemTask/SystemTask.cpp +++ b/src/SystemTask/SystemTask.cpp @@ -35,7 +35,8 @@ SystemTask::SystemTask(Drivers::SpiMaster &spi, Drivers::St7789 &lcd, twiMaster{twiMaster}, touchPanel{touchPanel}, lvgl{lvgl}, batteryController{batteryController}, bleController{bleController}, dateTimeController{dateTimeController}, watchdog{}, watchdogView{watchdog}, notificationManager{notificationManager}, - nimbleController(*this, bleController,dateTimeController, notificationManager, spiNorFlash) { + nimbleController(*this, bleController,dateTimeController, notificationManager, spiNorFlash), + bleMouse{nimbleController.GetHidService()}{ systemTaksMsgQueue = xQueueCreate(10, 1); } @@ -67,7 +68,7 @@ void SystemTask::Work() { batteryController.Init(); displayApp.reset(new Pinetime::Applications::DisplayApp(lcd, lvgl, touchPanel, batteryController, bleController, - dateTimeController, watchdogView, *this, notificationManager)); + dateTimeController, watchdogView, *this, notificationManager, bleMouse)); displayApp->Start(); batteryController.Update(); diff --git a/src/SystemTask/SystemTask.h b/src/SystemTask/SystemTask.h index 3812ea91..8fce1a1d 100644 --- a/src/SystemTask/SystemTask.h +++ b/src/SystemTask/SystemTask.h @@ -9,6 +9,7 @@ #include #include #include +#include #include "SystemMonitor.h" #include "Components/Ble/NimbleController.h" #include "timers.h" @@ -59,6 +60,7 @@ namespace Pinetime { Pinetime::Drivers::WatchdogView watchdogView; Pinetime::Controllers::NotificationManager& notificationManager; Pinetime::Controllers::NimbleController nimbleController; + Pinetime::Controllers::BleMouse bleMouse; static constexpr uint8_t pinSpiSck = 2;