nRF52840 BLE Serial 通讯
2021-12-12 本文已影响0人
T_K_233
Central Node
BLEClientBas clientBas; // battery client
BLEClientDis clientDis; // device information client
BLEClientUart clientUart; // bleuart client
void BLE_init(void) {
// Initialize Bluefruit with maximum connections as Peripheral = 0, Central = 1
// SRAM usage required by SoftDevice will increase dramatically with number of connections
Bluefruit.begin(0, 1);
Bluefruit.setName("CentralNode");
// Configure Battyer client
clientBas.begin();
// Configure DIS client
clientDis.begin();
// Init BLE Central Uart Serivce
clientUart.begin();
clientUart.setRxCallback(onBLE_UART_RXHandler);
// Increase Blink rate to different from PrPh advertising mode
Bluefruit.setConnLedInterval(250);
// Callbacks for Central
Bluefruit.Central.setConnectCallback(onConnectHandler);
Bluefruit.Central.setDisconnectCallback(onDisconnectHandler);
/* Start Central Scanning
* - Enable auto scan if disconnected
* - Interval = 100 ms, window = 80 ms
* - Don't use active scan
* - Start(timeout) with timeout = 0 will scan forever (until connected)
*/
Bluefruit.Scanner.setRxCallback(scan_callback);
Bluefruit.Scanner.restartOnDisconnect(true);
Bluefruit.Scanner.setInterval(160, 80); // in unit of 0.625 ms
Bluefruit.Scanner.useActiveScan(false);
Bluefruit.Scanner.start(0); // // 0 = Don't stop scanning after n seconds
}
/**
* Callback invoked when scanner pick up an advertising data
* @param report Structural advertising data
*/
void scan_callback(ble_gap_evt_adv_report_t* report) {
// Check if advertising contain BleUart service
if (Bluefruit.Scanner.checkReportForService(report, clientUart)) {
Serial.print("BLE UART service detected. Connecting ... ");
// Connect to device with bleuart service in advertising
Bluefruit.Central.connect(report);
}
else {
// For Softdevice v6: after received a report, scanner will be paused
// We need to call Scanner resume() to continue scanning
Bluefruit.Scanner.resume();
}
}
/**
* Callback invoked when an connection is established
* @param conn_handle
*/
void onConnectHandler(uint16_t conn_handle) {
Serial.println("Connected");
Serial.print("Dicovering Device Information ... ");
if (clientDis.discover(conn_handle)) {
Serial.println("Found it");
char buffer[32+1];
// read and print out Manufacturer
memset(buffer, 0, sizeof(buffer));
if (clientDis.getManufacturer(buffer, sizeof(buffer))) {
Serial.print("Manufacturer: ");
Serial.println(buffer);
}
// read and print out Model Number
memset(buffer, 0, sizeof(buffer));
if (clientDis.getModel(buffer, sizeof(buffer))) {
Serial.print("Model: ");
Serial.println(buffer);
}
Serial.println();
}
else {
Serial.println("Found NONE");
}
Serial.print("Dicovering Battery ... ");
if (clientBas.discover(conn_handle)) {
Serial.println("Found it");
Serial.print("Battery level: ");
Serial.print(clientBas.read());
Serial.println("%");
}
else {
Serial.println("Found NONE");
}
Serial.print("Discovering BLE Uart Service ... ");
if (clientUart.discover(conn_handle)) {
Serial.println("Found it");
Serial.println("Enable TXD's notify");
clientUart.enableTXD();
Serial.println("Ready to receive from peripheral");
}
else {
Serial.println("Found NONE");
// disconnect since we couldn't find bleuart service
Bluefruit.disconnect(conn_handle);
}
}
/**
* Callback invoked when a connection is dropped
* @param conn_handle
* @param reason is a BLE_HCI_STATUS_CODE which can be found in ble_hci.h
*/
void onDisconnectHandler(uint16_t conn_handle, uint8_t reason) {
(void) conn_handle;
(void) reason;
Serial.print("Disconnected, reason = 0x"); Serial.println(reason, HEX);
}
/**
* Callback invoked when uart received data
* @param uart_svc Reference object to the service where the data
* arrived. In this example it is clientUart
*/
void onBLE_UART_RXHandler(BLEClientUart& uart_svc) {
uart_svc.setTimeout(10);
if (uart_svc.available()) {
uint8_t buf[128];
uint16_t size = uart_svc.readBytesUntil('\n', buf, 128);
Serial.write(buf, size);
Serial.write('\n');
}
}
void setup() {
Serial.begin(115200);
while (!Serial) {}
Serial.setTimeout(10);
BLE_init();
}
void loop() {
if (Bluefruit.Central.connected() && clientUart.discovered()) {
// Discovered means in working state
// Get Serial input and send to Peripheral
if (Serial.available()) {
uint8_t buf[128];
uint16_t size = Serial.readBytesUntil('\n', buf, 128);
clientUart.write(buf, size);
//clientUart.write('\n');
}
}
}
Client
#include <bluefr#include <bluefruit.h>
// BLE Service
BLEDfu bledfu; // OTA DFU service
BLEDis bledis; // device information
BLEUart bleuart; // uart over ble
BLEBas blebas; // battery
// callback invoked when central connects
void onConnectHandler(uint16_t conn_handle) {
// Get the reference to current connection
BLEConnection* connection = Bluefruit.Connection(conn_handle);
char central_name[32] = { 0 };
connection->getPeerName(central_name, sizeof(central_name));
Serial.print("Connected to ");
Serial.println(central_name);
}
/**
* Callback invoked when a connection is dropped
* @param conn_handle connection where this event happens
* @param reason is a BLE_HCI_STATUS_CODE which can be found in ble_hci.h
*/
void onDisconnectHandler(uint16_t conn_handle, uint8_t reason) {
(void) conn_handle;
(void) reason;
Serial.println();
Serial.print("Disconnected, reason = 0x"); Serial.println(reason, HEX);
}
void BLE_init(void) {
// Setup the BLE LED to be enabled on CONNECT
// Note: This is actually the default behavior, but provided
// here in case you want to control this LED manually via PIN 19
Bluefruit.autoConnLed(true);
// Config the peripheral connection with maximum bandwidth
// more SRAM required by SoftDevice
// Note: All config***() function must be called before begin()
Bluefruit.configPrphBandwidth(BANDWIDTH_MAX);
Bluefruit.begin();
Bluefruit.setTxPower(4); // Check bluefruit.h for supported values
Bluefruit.setName("ClientNode"); // useful testing with multiple central connections
Bluefruit.Periph.setConnectCallback(onConnectHandler);
Bluefruit.Periph.setDisconnectCallback(onDisconnectHandler);
// To be consistent OTA DFU should be added first if it exists
bledfu.begin();
// Configure and Start Device Information Service
bledis.setManufacturer("RATH");
bledis.setModel("nRF52840");
bledis.begin();
// Configure and Start BLE Uart Service
bleuart.begin();
// Start BLE Battery Service
blebas.begin();
blebas.write(100);
}
void BLE_startAdvertising(void) {
// Advertising packet
Bluefruit.Advertising.addFlags(BLE_GAP_ADV_FLAGS_LE_ONLY_GENERAL_DISC_MODE);
Bluefruit.Advertising.addTxPower();
// Include bleuart 128-bit uuid
Bluefruit.Advertising.addService(bleuart);
// Secondary Scan Response packet (optional)
// Since there is no room for 'Name' in Advertising packet
Bluefruit.ScanResponse.addName();
/* Start Advertising
* - Enable auto advertising if disconnected
* - Interval: fast mode = 20 ms, slow mode = 152.5 ms
* - Timeout for fast mode is 30 seconds
* - Start(timeout) with timeout = 0 will advertise forever (until connected)
*
* For recommended advertising interval
* https://developer.apple.com/library/content/qa/qa1931/_index.html
*/
Bluefruit.Advertising.restartOnDisconnect(true);
Bluefruit.Advertising.setInterval(32, 244); // in unit of 0.625 ms
Bluefruit.Advertising.setFastTimeout(30); // number of seconds in fast mode
Bluefruit.Advertising.start(0); // 0 = Don't stop advertising after n seconds
}
void setup() {
Serial.begin(115200);
while (!Serial) {}
Serial.setTimeout(10);
bleuart.setTimeout(10);
BLE_init();
// Set up and start advertising
BLE_startAdvertising();
Serial.println("Please use Adafruit's Bluefruit LE app to connect in UART mode");
Serial.println("Once connected, enter character(s) that you wish to send");
}
void loop() {
if (Serial.available()) {
uint8_t buf[128];
uint16_t size = Serial.readBytesUntil('\n', buf, 128);
bleuart.write(buf, size);
//bleuart.write('\n');
}
if (bleuart.available()) {
uint8_t buf[128];
uint16_t size = bleuart.readBytesUntil('\n', buf, 128);
Serial.write(buf, size);
Serial.write('\n');
}
}
测试用的 Python 代码:
import random
import serial
ser = serial.Serial("COM20", 115200, timeout=0.01)
prev_t = time.time()
count = 0
counter = 0
while True:
t = time.time()
buf = "%s\n" % t
#buf = "hi\n"
counter += 1
ser.write(buf.encode())
time.sleep(0.005)
buf = b""
c = ser.read()
while c and c != b"\n":
buf += c
c = ser.read()
buf += c
count += len(buf)
#print(buf)
try:
prev_t = float(buf.decode().replace("\n", ""))
print(t, "\t", time.time() - prev_t)
except:
pass
if count > 100:
print(count / (time.time() - prev_t), " wd/s")
count = 0
prev_t = time.time()
另一端用个 echo client
import serial
ser = serial.Serial("COM23", 115200, timeout=0.1)
count = 0
while True:
buf = b""
c = ser.read()
while c and c != b"\n":
buf += c
c = ser.read()
buf += c
#print(buf)
ser.write(buf)
count += 1