rctank.txt youtube https://www.youtube.com/watch?v=2MBNl4xFADI /******************* main.dart *********************/ import 'package:flutter/material.dart'; import 'package:get/get.dart'; import 'package:arrow_pad/arrow_pad.dart'; import 'package:flutter_reactive_ble/flutter_reactive_ble.dart'; import 'dart:async'; import 'dart:typed_data'; void main() {runApp(MainApp());} class MainApp extends StatelessWidget { MainApp({super.key}); String _value = ' '; List packet=[0,0]; late BleController ble; @override Widget build(BuildContext context) { ble=Get.put(BleController()); double height = MediaQuery.of(context).size.height; double width = MediaQuery.of(context).size.width; return MaterialApp( home: Scaffold( body: Center(child: SingleChildScrollView(child: Column( mainAxisAlignment: MainAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.center, children: [ //////////// connect button ElevatedButton(child: Obx(()=>Text('${ble.status.value}')), onPressed:ble.connect), SizedBox(height:50), ////////////arrow pad ArrowPad( padding: const EdgeInsets.all(8.0), height: height / 3, width: width / 2, arrowPadIconStyle: ArrowPadIconStyle.arrow, hoverColor: Colors.green, iconColor: const Color(0xFF631739), outerColor: const Color(0xFF86FC8A), clickTrigger: ClickTrigger.onTapUp, onPressed: (dir){ if (dir.toString().compareTo('right') == 0) { packet[1] = 0x72; ble.send(packet);} else if (dir.toString().compareTo('left') == 0) { packet[1] = 0x6C; ble.send(packet);} else if (dir.toString().compareTo('up') == 0) { packet[1] = 0x75; ble.send(packet);} else if (dir.toString().compareTo('down') == 0) { packet[1] = 0x64; ble.send(packet);} }), SizedBox(height:50), ///////// exit button ElevatedButton(child: Text('stop'), onPressed:(){packet[1] = 0x73; ble.send(packet);}), ]))) ));}} class BleController { final frb = FlutterReactiveBle(); late StreamSubscription c; late QualifiedCharacteristic tx; var status = 'connect to bluetooth'.obs; void send(val) async{ // print(val);} await frb.writeCharacteristicWithoutResponse(tx, value: val);} void connect() async { status.value = 'connecting...'; c = frb.connectToDevice(id: '28:CD:C1:08:28:9E').listen((state) { if (state.connectionState == DeviceConnectionState.connected) { status.value = 'connected!'; tx = QualifiedCharacteristic( serviceId: Uuid.parse("6e400001-b5a3-f393-e0a9-e50e24dcca9e"), characteristicId: Uuid.parse("6e400002-b5a3-f393-e0a9-e50e24dcca9e"), deviceId: '28:CD:C1:08:28:9E'); }});}} /*************** main.c ******************/ #include "pico/stdlib.h" #include "hardware/gpio.h" #include "pico/stdlib.h" #include "pico/multicore.h" #include "blink.h" uint8_t old_data = 0; struct bt_type data; void main(void){ stdio_init_all(); sleep_ms(1000); gpio_init(10); gpio_set_dir(10,GPIO_OUT); gpio_init(11); gpio_set_dir(11,GPIO_OUT); gpio_init(14); gpio_set_dir(14,GPIO_OUT); gpio_init(15); gpio_set_dir(15,GPIO_OUT); multicore_launch_core1(bt_main); sleep_ms(1000); for(;;){ sleep_ms(100); bt_get_latest(&data); if (old_data != data.data){ switch(data.data){ // backward case 'b': gpio_put(10,1); gpio_put(11,0); gpio_put(14,1); gpio_put(14,0); break; // forward case 'f': gpio_put(10,0); gpio_put(11,1); gpio_put(14,0); gpio_put(14,1); break; // left case 'l': gpio_put(10,0); gpio_put(11,1); gpio_put(14,1); gpio_put(14,0); break; // right case 'r': gpio_put(10,1); gpio_put(11,0); gpio_put(14,0); gpio_put(14,1); break; // stop case 's': gpio_put(10,1); gpio_put(11,1); gpio_put(14,1); gpio_put(14,1); break; } old_data = data.data; }}} /**************** mygatt.gatt *****************/ PRIMARY_SERVICE, GAP_SERVICE CHARACTERISTIC, GAP_DEVICE_NAME, READ, "Nordic SPP Counter" #import /******************** CMakeLists.txt *********************/ cmake_minimum_required(VERSION 3.12) set(PICO_SDK_PATH "/home/sonny/pico/pico-sdk") set(PICO_SDK_POST_LIST_DIRS "/home/sonny/pico/pico-extras") set(PICO_BOARD "pico_w") include("${PICO_SDK_PATH}/external/pico_sdk_import.cmake") include("${PICO_SDK_POST_LIST_DIRS}/external/pico_extras_import.cmake") project(blink_v1 C CXX ASM) set(CMAKE_C_STANDARD 11) set(CMAKE_CXX_STANDARD 17) pico_sdk_init() add_executable(blink_v1 main.c blink.c ) target_link_libraries(blink_v1 pico_stdlib hardware_gpio pico_btstack_ble pico_btstack_cyw43 pico_btstack_classic pico_cyw43_arch_none pico_multicore ) pico_enable_stdio_usb(blink_v1 0) pico_enable_stdio_uart(blink_v1 1) target_include_directories(blink_v1 PRIVATE ${CMAKE_CURRENT_LIST_DIR} ) pico_btstack_make_gatt_header(blink_v1 PRIVATE "${CMAKE_CURRENT_LIST_DIR}/mygatt.gatt") pico_add_extra_outputs(blink_v1) /************* blink.h *******************/ void bt_main(void); struct bt_type{ uint8_t code; uint8_t data;}; void bt_get_latest(struct bt_type *dst); /********************* blink.c **********************/ #include #include #include #include #include "btstack_run_loop.h" #include "pico/stdlib.h" #include "btstack_config.h" #include "btstack_event.h" #include "pico/cyw43_arch.h" #include "pico/btstack_cyw43.h" #include "pico/async_context.h" #include "hal_led.h" #include "btstack.h" #include "ble/gatt-service/nordic_spp_service_server.h" #include "mygatt.h" #include "blink.h" static hci_con_handle_t con_handle = HCI_CON_HANDLE_INVALID; static btstack_context_callback_registration_t send_request; static btstack_packet_callback_registration_t hci_event_callback_registration; struct bt_type latest; const uint8_t adv_data[] = { 2, BLUETOOTH_DATA_TYPE_FLAGS, 0x06, 8, BLUETOOTH_DATA_TYPE_COMPLETE_LOCAL_NAME, 'n', 'R', 'F',' ', 'S', 'P', 'P', 17, BLUETOOTH_DATA_TYPE_COMPLETE_LIST_OF_128_BIT_SERVICE_CLASS_UUIDS, 0x9e, 0xca, 0xdc, 0x24, 0xe, 0xe5, 0xa9, 0xe0, 0x93, 0xf3, 0xa3, 0xb5, 0x1, 0x0, 0x40, 0x6e,}; const uint8_t adv_data_len = sizeof(adv_data); static void hci_packet_handler (uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){ UNUSED(channel); UNUSED(size); if (packet_type != HCI_EVENT_PACKET) return; switch (hci_event_packet_get_type(packet)) { case HCI_EVENT_DISCONNECTION_COMPLETE: con_handle = HCI_CON_HANDLE_INVALID; break; default: break;}} static void nordic_spp_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){ UNUSED(channel); switch (packet_type){ case HCI_EVENT_PACKET: if (hci_event_packet_get_type(packet) != HCI_EVENT_GATTSERVICE_META) break; switch (hci_event_gattservice_meta_get_subevent_code(packet)){ case GATTSERVICE_SUBEVENT_SPP_SERVICE_CONNECTED: con_handle = gattservice_subevent_spp_service_connected_get_con_handle(packet); break; case GATTSERVICE_SUBEVENT_SPP_SERVICE_DISCONNECTED: con_handle = HCI_CON_HANDLE_INVALID; break; default: break; } break; case RFCOMM_DATA_PACKET: latest.code = packet[0]; latest.data = packet[1]; break; default: break; }} void bt_get_latest(struct bt_type *dst){ async_context_t *context = cyw43_arch_async_context(); async_context_acquire_lock_blocking(context); memcpy(dst, &latest, sizeof(*dst)); async_context_release_lock(context);} void bt_main(void){ cyw43_arch_init(); hci_event_callback_registration.callback = &hci_packet_handler; hci_add_event_handler(&hci_event_callback_registration); l2cap_init(); sm_init(); att_server_init(profile_data, NULL, NULL); nordic_spp_service_server_init(&nordic_spp_packet_handler); uint16_t adv_int_min = 0x0030; uint16_t adv_int_max = 0x0030; uint8_t adv_type = 0; bd_addr_t null_addr; memset(null_addr, 0, 6); gap_advertisements_set_params(adv_int_min, adv_int_max, adv_type, 0, null_addr, 0x07, 0x00); gap_advertisements_set_data(adv_data_len, (uint8_t*) adv_data); gap_advertisements_enable(1); hci_power_control(HCI_POWER_ON); btstack_run_loop_execute();}