Finish firmware private transport stack

This commit is contained in:
2026-04-11 13:53:34 +08:00
parent 30f1af1a8c
commit a8e0cfe1b3
12 changed files with 480 additions and 72 deletions

View File

@@ -17,6 +17,14 @@ find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE})
project(new_kbd) project(new_kbd)
if(NOT c_std_11 IN_LIST CMAKE_C_COMPILE_FEATURES)
list(APPEND CMAKE_C_COMPILE_FEATURES c_std_11)
endif()
set(PROTOBUF_PROTOC_EXECUTABLE
"${CMAKE_CURRENT_SOURCE_DIR}/scripts/protoc_nanopb.bat"
CACHE FILEPATH "Project-local protoc wrapper for nanopb" FORCE)
list(APPEND CMAKE_MODULE_PATH ${ZEPHYR_BASE}/modules/nanopb) list(APPEND CMAKE_MODULE_PATH ${ZEPHYR_BASE}/modules/nanopb)
include(nanopb) include(nanopb)
@@ -40,6 +48,8 @@ zephyr_nanopb_sources(app
KeyBorad/proto/keyboard.proto KeyBorad/proto/keyboard.proto
) )
target_link_libraries(app PRIVATE nanopb)
target_sources(app PRIVATE target_sources(app PRIVATE
src/main.c src/main.c
src/events/battery_status_event.c src/events/battery_status_event.c

View File

@@ -1,10 +1,210 @@
#include "DRI/GATT/Dri_Gatt.h" #include "DRI/GATT/Dri_Gatt.h"
#include <QtBluetooth/QBluetoothAddress>
#include <QtBluetooth/QBluetoothDeviceDiscoveryAgent> #include <QtBluetooth/QBluetoothDeviceDiscoveryAgent>
#include <QtBluetooth/QBluetoothDeviceInfo> #include <QtBluetooth/QBluetoothDeviceInfo>
#include <QtBluetooth/QBluetoothUuid>
#include <QtBluetooth/QLowEnergyCharacteristic>
#include <QtBluetooth/QLowEnergyController>
#include <QtBluetooth/QLowEnergyDescriptor>
#include <QtBluetooth/QLowEnergyService>
#include <QtCore/QEventLoop> #include <QtCore/QEventLoop>
#include <QtCore/QList>
#include <QtCore/QTimer> #include <QtCore/QTimer>
struct Dri_Gatt_Struct_Context
{
QLowEnergyController* Controller = nullptr;
QLowEnergyService* Service = nullptr;
QLowEnergyCharacteristic RxCharacteristic;
QLowEnergyCharacteristic TxCharacteristic;
QList<QByteArray> ReadQueue;
};
namespace
{
const QBluetoothUuid kServiceUuid(
QStringLiteral("0b7f6000-38d2-4f62-8f6f-36c4fd73a110"));
const QBluetoothUuid kRxUuid(
QStringLiteral("0b7f6001-38d2-4f62-8f6f-36c4fd73a110"));
const QBluetoothUuid kTxUuid(
QStringLiteral("0b7f6002-38d2-4f62-8f6f-36c4fd73a110"));
bool Dri_Gatt_Func_WaitForControllerConnected(QLowEnergyController* p_Controller)
{
QEventLoop EventLoop;
QTimer TimeoutTimer;
bool IsConnected = false;
TimeoutTimer.setSingleShot(true);
QObject::connect(
p_Controller,
&QLowEnergyController::connected,
&EventLoop,
[&EventLoop, &IsConnected]()
{
IsConnected = true;
EventLoop.quit();
});
QObject::connect(
p_Controller,
static_cast<void (QLowEnergyController::*)(QLowEnergyController::Error)>(
&QLowEnergyController::error),
&EventLoop,
[&EventLoop]()
{
EventLoop.quit();
});
QObject::connect(
&TimeoutTimer,
&QTimer::timeout,
&EventLoop,
&QEventLoop::quit);
p_Controller->connectToDevice();
TimeoutTimer.start(5000);
EventLoop.exec();
return IsConnected;
}
bool Dri_Gatt_Func_WaitForServiceDiscovery(QLowEnergyController* p_Controller)
{
QEventLoop EventLoop;
QTimer TimeoutTimer;
bool IsFinished = false;
TimeoutTimer.setSingleShot(true);
QObject::connect(
p_Controller,
&QLowEnergyController::discoveryFinished,
&EventLoop,
[&EventLoop, &IsFinished]()
{
IsFinished = true;
EventLoop.quit();
});
QObject::connect(
p_Controller,
static_cast<void (QLowEnergyController::*)(QLowEnergyController::Error)>(
&QLowEnergyController::error),
&EventLoop,
[&EventLoop]()
{
EventLoop.quit();
});
QObject::connect(
&TimeoutTimer,
&QTimer::timeout,
&EventLoop,
&QEventLoop::quit);
p_Controller->discoverServices();
TimeoutTimer.start(5000);
EventLoop.exec();
return IsFinished;
}
bool Dri_Gatt_Func_WaitForServiceDetails(QLowEnergyService* p_Service)
{
QEventLoop EventLoop;
QTimer TimeoutTimer;
bool IsDiscovered = false;
TimeoutTimer.setSingleShot(true);
QObject::connect(
p_Service,
&QLowEnergyService::stateChanged,
&EventLoop,
[&EventLoop, &IsDiscovered](QLowEnergyService::ServiceState State)
{
if (State == QLowEnergyService::ServiceDiscovered)
{
IsDiscovered = true;
EventLoop.quit();
}
});
QObject::connect(
p_Service,
static_cast<void (QLowEnergyService::*)(QLowEnergyService::ServiceError)>(
&QLowEnergyService::error),
&EventLoop,
[&EventLoop]()
{
EventLoop.quit();
});
QObject::connect(
&TimeoutTimer,
&QTimer::timeout,
&EventLoop,
&QEventLoop::quit);
p_Service->discoverDetails();
TimeoutTimer.start(5000);
EventLoop.exec();
return IsDiscovered;
}
bool Dri_Gatt_Func_EnableNotify(
Dri_Gatt_Struct_Context* p_Context,
const QLowEnergyCharacteristic& Characteristic)
{
if (!Characteristic.isValid() || (p_Context == nullptr) || (p_Context->Service == nullptr))
{
return false;
}
const QLowEnergyDescriptor Cccd =
Characteristic.descriptor(QBluetoothUuid::ClientCharacteristicConfiguration);
if (!Cccd.isValid())
{
return false;
}
QEventLoop EventLoop;
QTimer TimeoutTimer;
bool IsWritten = false;
TimeoutTimer.setSingleShot(true);
QObject::connect(
p_Context->Service,
&QLowEnergyService::descriptorWritten,
&EventLoop,
[&EventLoop, &IsWritten, Cccd](const QLowEnergyDescriptor& Descriptor, const QByteArray&)
{
if (Descriptor == Cccd)
{
IsWritten = true;
EventLoop.quit();
}
});
QObject::connect(
p_Context->Service,
static_cast<void (QLowEnergyService::*)(QLowEnergyService::ServiceError)>(
&QLowEnergyService::error),
&EventLoop,
[&EventLoop]()
{
EventLoop.quit();
});
QObject::connect(
&TimeoutTimer,
&QTimer::timeout,
&EventLoop,
&QEventLoop::quit);
p_Context->Service->writeDescriptor(Cccd, QByteArray::fromHex("0100"));
TimeoutTimer.start(3000);
EventLoop.exec();
return IsWritten;
}
} // namespace
QVector<Dri_Gatt_Struct_PortInfo> Dri_Gatt_Enum() QVector<Dri_Gatt_Struct_PortInfo> Dri_Gatt_Enum()
{ {
QVector<Dri_Gatt_Struct_PortInfo> PortList; QVector<Dri_Gatt_Struct_PortInfo> PortList;
@@ -79,6 +279,17 @@ void Dri_Gatt_Close(Dri_Gatt_Struct_Port* p_Port)
return; return;
} }
if (p_Port->p_Context != nullptr)
{
if (p_Port->p_Context->Controller != nullptr)
{
p_Port->p_Context->Controller->disconnectFromDevice();
delete p_Port->p_Context->Controller;
}
delete p_Port->p_Context;
}
*p_Port = Dri_Gatt_Struct_Port(); *p_Port = Dri_Gatt_Struct_Port();
} }
@@ -93,38 +304,183 @@ bool Dri_Gatt_Open(
} }
Dri_Gatt_Close(p_Port); Dri_Gatt_Close(p_Port);
Dri_Gatt_Struct_Context* const p_Context = new Dri_Gatt_Struct_Context();
p_Context->Controller = new QLowEnergyController(QBluetoothAddress(DeviceAddress.trimmed()));
if (!Dri_Gatt_Func_WaitForControllerConnected(p_Context->Controller))
{
Dri_Gatt_Close(p_Port);
delete p_Context->Controller;
delete p_Context;
return false;
}
if (!Dri_Gatt_Func_WaitForServiceDiscovery(p_Context->Controller) ||
!p_Context->Controller->services().contains(kServiceUuid))
{
Dri_Gatt_Close(p_Port);
delete p_Context->Controller;
delete p_Context;
return false;
}
p_Context->Service = p_Context->Controller->createServiceObject(kServiceUuid, p_Context->Controller);
if (p_Context->Service == nullptr)
{
Dri_Gatt_Close(p_Port);
delete p_Context->Controller;
delete p_Context;
return false;
}
if (!Dri_Gatt_Func_WaitForServiceDetails(p_Context->Service))
{
Dri_Gatt_Close(p_Port);
delete p_Context->Controller;
delete p_Context;
return false;
}
p_Context->RxCharacteristic = p_Context->Service->characteristic(kRxUuid);
p_Context->TxCharacteristic = p_Context->Service->characteristic(kTxUuid);
if (!p_Context->RxCharacteristic.isValid() || !p_Context->TxCharacteristic.isValid())
{
Dri_Gatt_Close(p_Port);
delete p_Context->Controller;
delete p_Context;
return false;
}
QObject::connect(
p_Context->Service,
&QLowEnergyService::characteristicChanged,
[p_Context](const QLowEnergyCharacteristic& Characteristic, const QByteArray& Value)
{
if (Characteristic == p_Context->TxCharacteristic)
{
p_Context->ReadQueue.append(Value);
}
});
if (!Dri_Gatt_Func_EnableNotify(p_Context, p_Context->TxCharacteristic))
{
Dri_Gatt_Close(p_Port);
delete p_Context->Controller;
delete p_Context;
return false;
}
p_Port->p_Context = p_Context;
p_Port->IsOpened = true; p_Port->IsOpened = true;
p_Port->DeviceAddress = DeviceAddress.trimmed(); p_Port->DeviceAddress = DeviceAddress.trimmed();
return false; return true;
} }
bool Dri_Gatt_ReadBytes( bool Dri_Gatt_ReadBytes(
Dri_Gatt_Struct_Port* p_Port, Dri_Gatt_Struct_Port* p_Port,
QByteArray* p_ByteArray, QByteArray* p_ByteArray,
int) int TimeoutMs)
{ {
if (p_ByteArray != nullptr) if (p_ByteArray != nullptr)
{ {
p_ByteArray->clear(); p_ByteArray->clear();
} }
if ((p_Port == nullptr) || (p_ByteArray == nullptr) || !p_Port->IsOpened) if ((p_Port == nullptr) || (p_ByteArray == nullptr) ||
!p_Port->IsOpened || (p_Port->p_Context == nullptr))
{ {
return false; return false;
} }
if (p_Port->p_Context->ReadQueue.isEmpty() && (TimeoutMs > 0))
{
QEventLoop EventLoop;
QTimer TimeoutTimer;
TimeoutTimer.setSingleShot(true);
QObject::connect(
p_Port->p_Context->Service,
&QLowEnergyService::characteristicChanged,
&EventLoop,
[&EventLoop](const QLowEnergyCharacteristic&, const QByteArray&)
{
EventLoop.quit();
});
QObject::connect(
&TimeoutTimer,
&QTimer::timeout,
&EventLoop,
&QEventLoop::quit);
TimeoutTimer.start(TimeoutMs);
EventLoop.exec();
}
if (p_Port->p_Context->ReadQueue.isEmpty())
{
return false; return false;
} }
*p_ByteArray = p_Port->p_Context->ReadQueue.takeFirst();
return !p_ByteArray->isEmpty();
}
bool Dri_Gatt_WriteBytes( bool Dri_Gatt_WriteBytes(
Dri_Gatt_Struct_Port* p_Port, Dri_Gatt_Struct_Port* p_Port,
const QByteArray& ByteArray, const QByteArray& ByteArray,
int) int TimeoutMs)
{ {
if ((p_Port == nullptr) || !p_Port->IsOpened) if ((p_Port == nullptr) || !p_Port->IsOpened || (p_Port->p_Context == nullptr))
{ {
return false; return false;
} }
return !ByteArray.isEmpty(); if (ByteArray.isEmpty())
{
return false;
}
QEventLoop EventLoop;
QTimer TimeoutTimer;
bool IsWritten = false;
TimeoutTimer.setSingleShot(true);
QObject::connect(
p_Port->p_Context->Service,
&QLowEnergyService::characteristicWritten,
&EventLoop,
[&EventLoop, &IsWritten, p_Port](const QLowEnergyCharacteristic& Characteristic, const QByteArray&)
{
if (Characteristic == p_Port->p_Context->RxCharacteristic)
{
IsWritten = true;
EventLoop.quit();
}
});
QObject::connect(
p_Port->p_Context->Service,
static_cast<void (QLowEnergyService::*)(QLowEnergyService::ServiceError)>(
&QLowEnergyService::error),
&EventLoop,
[&EventLoop]()
{
EventLoop.quit();
});
QObject::connect(
&TimeoutTimer,
&QTimer::timeout,
&EventLoop,
&QEventLoop::quit);
p_Port->p_Context->Service->writeCharacteristic(
p_Port->p_Context->RxCharacteristic,
ByteArray,
QLowEnergyService::WriteWithResponse);
TimeoutTimer.start(TimeoutMs > 0 ? TimeoutMs : 3000);
EventLoop.exec();
return IsWritten;
} }

View File

@@ -4,6 +4,8 @@
#include <QtCore/QString> #include <QtCore/QString>
#include <QtCore/QVector> #include <QtCore/QVector>
struct Dri_Gatt_Struct_Context;
struct Dri_Gatt_Struct_PortInfo struct Dri_Gatt_Struct_PortInfo
{ {
QString DeviceName; QString DeviceName;
@@ -17,7 +19,9 @@ struct Dri_Gatt_Struct_OpenConfig
struct Dri_Gatt_Struct_Port struct Dri_Gatt_Struct_Port
{ {
bool IsOpened = false; bool IsOpened = false;
QString DeviceName;
QString DeviceAddress; QString DeviceAddress;
Dri_Gatt_Struct_Context* p_Context = nullptr;
}; };
QVector<Dri_Gatt_Struct_PortInfo> Dri_Gatt_Enum(); QVector<Dri_Gatt_Struct_PortInfo> Dri_Gatt_Enum();

View File

@@ -1,2 +1,2 @@
CdcFrame.payload max_size:64 keyboard.cdc.CdcFrame.payload max_size:64
Bitmap.usage_bitmap max_size:29 keyboard.cdc.Bitmap.usage_bitmap max_size:29

View File

@@ -36,7 +36,7 @@
}; };
}; };
&zephyr_udc0 { &usbd {
cdc_acm_uart0: cdc_acm_uart0 { cdc_acm_uart0: cdc_acm_uart0 {
compatible = "zephyr,cdc-acm-uart"; compatible = "zephyr,cdc-acm-uart";
label = "new_kbd CDC ACM"; label = "new_kbd CDC ACM";

View File

@@ -80,6 +80,8 @@ Implemented behavior:
- enable CDC ACM class in Zephyr USB device-next stack - enable CDC ACM class in Zephyr USB device-next stack
- add a CDC ACM UART node in devicetree - add a CDC ACM UART node in devicetree
- wire `zephyr_nanopb_sources()` into the build - wire `zephyr_nanopb_sources()` into the build
- force nanopb generation to use the NCS toolchain Python instead of the
broken Windows app alias
- add protocol helper functions for: - add protocol helper functions for:
- body encode/decode - body encode/decode
- CDC frame encode - CDC frame encode

View File

@@ -62,7 +62,30 @@ Implemented behavior:
- collect device name and address - collect device name and address
- filter to `LowEnergyCoreConfiguration` - filter to `LowEnergyCoreConfiguration`
- stop after a short timeout - stop after a short timeout
### Node 3: CDC transport cleanup
### Node 3: GATT open and raw byte transport
Files updated in this step:
- `KeyBorad/KeyBorad/DRI/GATT/Dri_Gatt.h`
- `KeyBorad/KeyBorad/DRI/GATT/Dri_Gatt.cpp`
Design notes:
- keep transport-only responsibility
- use Qt Bluetooth instead of custom Win32 BLE code
- connect, discover service, subscribe, then pass raw bytes upward
Implemented behavior:
- connect to a BLE device by address
- discover the target custom service
- resolve RX/TX characteristics
- enable notify on TX
- queue raw bytes from TX notify
- write raw bytes to RX characteristic
### Node 4: CDC transport cleanup
Files updated in this step: Files updated in this step:

View File

@@ -20,11 +20,11 @@ enum keyboard_proto_transport {
}; };
typedef bool (*keyboard_proto_send_body_fn)( typedef bool (*keyboard_proto_send_body_fn)(
const struct keyboard_cdc_CdcPacketBody *body, const keyboard_cdc_CdcPacketBody *body,
void *user_data); void *user_data);
bool keyboard_proto_encode_body( bool keyboard_proto_encode_body(
const struct keyboard_cdc_CdcPacketBody *body, const keyboard_cdc_CdcPacketBody *body,
uint8_t *buffer, uint8_t *buffer,
size_t buffer_size, size_t buffer_size,
size_t *encoded_size); size_t *encoded_size);
@@ -32,11 +32,11 @@ bool keyboard_proto_encode_body(
bool keyboard_proto_decode_body( bool keyboard_proto_decode_body(
const uint8_t *buffer, const uint8_t *buffer,
size_t buffer_size, size_t buffer_size,
struct keyboard_cdc_CdcPacketBody *body); keyboard_cdc_CdcPacketBody *body);
bool keyboard_proto_encode_cdc_frame( bool keyboard_proto_encode_cdc_frame(
uint32_t packet_type, uint32_t packet_type,
const struct keyboard_cdc_CdcPacketBody *body, const keyboard_cdc_CdcPacketBody *body,
uint8_t *buffer, uint8_t *buffer,
size_t buffer_size, size_t buffer_size,
size_t *encoded_size); size_t *encoded_size);
@@ -44,19 +44,19 @@ bool keyboard_proto_encode_cdc_frame(
bool keyboard_proto_try_take_cdc_frame( bool keyboard_proto_try_take_cdc_frame(
uint8_t *buffer, uint8_t *buffer,
size_t *buffer_size, size_t *buffer_size,
struct keyboard_cdc_CdcFrame *frame); keyboard_cdc_CdcFrame *frame);
bool keyboard_proto_build_function_key_event_body( bool keyboard_proto_build_function_key_event_body(
uint16_t usage, uint16_t usage,
bool pressed, bool pressed,
struct keyboard_cdc_CdcPacketBody *body); keyboard_cdc_CdcPacketBody *body);
bool keyboard_proto_build_led_state_body( bool keyboard_proto_build_led_state_body(
uint8_t led_mask, uint8_t led_mask,
struct keyboard_cdc_CdcPacketBody *body); keyboard_cdc_CdcPacketBody *body);
bool keyboard_proto_handle_host_body( bool keyboard_proto_handle_host_body(
const struct keyboard_cdc_CdcPacketBody *body, const keyboard_cdc_CdcPacketBody *body,
enum keyboard_proto_transport transport, enum keyboard_proto_transport transport,
keyboard_proto_send_body_fn send_fn, keyboard_proto_send_body_fn send_fn,
void *user_data); void *user_data);

View File

@@ -0,0 +1,5 @@
@echo off
setlocal
set PATH=C:\ncs\toolchains\fd21892d0f\opt\bin;%PATH%
"C:\ncs\toolchains\fd21892d0f\opt\bin\python.exe" "C:\ncs\v3.2.4\modules\lib\nanopb\generator\protoc" %*
exit /b %ERRORLEVEL%

View File

@@ -32,6 +32,9 @@ struct ble_gatt_proto_ctx {
}; };
static struct ble_gatt_proto_ctx g_ble_proto; static struct ble_gatt_proto_ctx g_ble_proto;
static bool ble_gatt_proto_send_body(
const keyboard_cdc_CdcPacketBody *body,
void *user_data);
static void ble_gatt_proto_ccc_changed( static void ble_gatt_proto_ccc_changed(
const struct bt_gatt_attr *attr, const struct bt_gatt_attr *attr,
@@ -50,7 +53,7 @@ static ssize_t ble_gatt_proto_rx_write(
uint16_t offset, uint16_t offset,
uint8_t flags) uint8_t flags)
{ {
struct keyboard_cdc_CdcPacketBody body; keyboard_cdc_CdcPacketBody body;
ARG_UNUSED(conn); ARG_UNUSED(conn);
ARG_UNUSED(attr); ARG_UNUSED(attr);
@@ -96,7 +99,7 @@ BT_GATT_SERVICE_DEFINE(
BT_GATT_PERM_READ | BT_GATT_PERM_WRITE)); BT_GATT_PERM_READ | BT_GATT_PERM_WRITE));
static bool ble_gatt_proto_send_body( static bool ble_gatt_proto_send_body(
const struct keyboard_cdc_CdcPacketBody *body, const keyboard_cdc_CdcPacketBody *body,
void *user_data) void *user_data)
{ {
uint8_t buffer[KEYBOARD_PROTO_MAX_BODY_SIZE]; uint8_t buffer[KEYBOARD_PROTO_MAX_BODY_SIZE];
@@ -128,7 +131,7 @@ static bool handle_module_state_event(const struct module_state_event *event)
static bool handle_function_key_event(const struct function_key_event *event) static bool handle_function_key_event(const struct function_key_event *event)
{ {
struct keyboard_cdc_CdcPacketBody body; keyboard_cdc_CdcPacketBody body;
if (!keyboard_proto_build_function_key_event_body(event->usage, if (!keyboard_proto_build_function_key_event_body(event->usage,
event->pressed, event->pressed,
@@ -142,7 +145,7 @@ static bool handle_function_key_event(const struct function_key_event *event)
static bool handle_keyboard_led_event(const struct keyboard_led_event *event) static bool handle_keyboard_led_event(const struct keyboard_led_event *event)
{ {
struct keyboard_cdc_CdcPacketBody body; keyboard_cdc_CdcPacketBody body;
if (!keyboard_proto_build_led_state_body( if (!keyboard_proto_build_led_state_body(
keyboard_led_event_get_mask(event), keyboard_led_event_get_mask(event),

View File

@@ -3,6 +3,7 @@
#include <string.h> #include <string.h>
#include <zephyr/sys/byteorder.h> #include <zephyr/sys/byteorder.h>
#include <zephyr/sys/util.h>
#include "display_theme_event.h" #include "display_theme_event.h"
#include "function_bitmap_event.h" #include "function_bitmap_event.h"
@@ -48,23 +49,8 @@ static uint8_t keyboard_proto_calc_checksum(const uint8_t *data, size_t len)
return checksum; return checksum;
} }
static bool keyboard_proto_fill_payload(
pb_bytes_array_t *dest,
size_t max_size,
const uint8_t *src,
size_t src_len)
{
if ((dest == NULL) || (src == NULL) || (src_len > max_size)) {
return false;
}
dest->size = src_len;
memcpy(dest->bytes, src, src_len);
return true;
}
bool keyboard_proto_encode_body( bool keyboard_proto_encode_body(
const struct keyboard_cdc_CdcPacketBody *body, const keyboard_cdc_CdcPacketBody *body,
uint8_t *buffer, uint8_t *buffer,
size_t buffer_size, size_t buffer_size,
size_t *encoded_size) size_t *encoded_size)
@@ -88,7 +74,7 @@ bool keyboard_proto_encode_body(
bool keyboard_proto_decode_body( bool keyboard_proto_decode_body(
const uint8_t *buffer, const uint8_t *buffer,
size_t buffer_size, size_t buffer_size,
struct keyboard_cdc_CdcPacketBody *body) keyboard_cdc_CdcPacketBody *body)
{ {
pb_istream_t stream; pb_istream_t stream;
@@ -96,7 +82,10 @@ bool keyboard_proto_decode_body(
return false; return false;
} }
*body = keyboard_cdc_CdcPacketBody_init_zero; {
keyboard_cdc_CdcPacketBody empty = keyboard_cdc_CdcPacketBody_init_zero;
*body = empty;
}
stream = pb_istream_from_buffer(buffer, buffer_size); stream = pb_istream_from_buffer(buffer, buffer_size);
if (!pb_decode(&stream, keyboard_cdc_CdcPacketBody_fields, body)) { if (!pb_decode(&stream, keyboard_cdc_CdcPacketBody_fields, body)) {
@@ -108,12 +97,12 @@ bool keyboard_proto_decode_body(
bool keyboard_proto_encode_cdc_frame( bool keyboard_proto_encode_cdc_frame(
uint32_t packet_type, uint32_t packet_type,
const struct keyboard_cdc_CdcPacketBody *body, const keyboard_cdc_CdcPacketBody *body,
uint8_t *buffer, uint8_t *buffer,
size_t buffer_size, size_t buffer_size,
size_t *encoded_size) size_t *encoded_size)
{ {
struct keyboard_cdc_CdcFrame frame = keyboard_cdc_CdcFrame_init_zero; keyboard_cdc_CdcFrame frame = keyboard_cdc_CdcFrame_init_zero;
uint8_t payload[KEYBOARD_PROTO_MAX_BODY_SIZE]; uint8_t payload[KEYBOARD_PROTO_MAX_BODY_SIZE];
size_t payload_size = 0U; size_t payload_size = 0U;
pb_ostream_t stream; pb_ostream_t stream;
@@ -131,10 +120,11 @@ bool keyboard_proto_encode_cdc_frame(
frame.head2 = 0x55U; frame.head2 = 0x55U;
frame.payload_length = payload_size; frame.payload_length = payload_size;
frame.type = (keyboard_cdc_CdcPacketType)packet_type; frame.type = (keyboard_cdc_CdcPacketType)packet_type;
if (!keyboard_proto_fill_payload(&frame.payload, KEYBOARD_PROTO_MAX_BODY_SIZE, if (payload_size > KEYBOARD_PROTO_MAX_BODY_SIZE) {
payload, payload_size)) {
return false; return false;
} }
frame.payload.size = payload_size;
memcpy(frame.payload.bytes, payload, payload_size);
checksum_bytes[0] = (uint8_t)frame.head1; checksum_bytes[0] = (uint8_t)frame.head1;
checksum_bytes[1] = (uint8_t)frame.head2; checksum_bytes[1] = (uint8_t)frame.head2;
@@ -154,7 +144,7 @@ bool keyboard_proto_encode_cdc_frame(
return true; return true;
} }
static bool keyboard_proto_validate_frame(const struct keyboard_cdc_CdcFrame *frame) static bool keyboard_proto_validate_frame(const keyboard_cdc_CdcFrame *frame)
{ {
uint8_t checksum_bytes[4U + KEYBOARD_PROTO_MAX_BODY_SIZE]; uint8_t checksum_bytes[4U + KEYBOARD_PROTO_MAX_BODY_SIZE];
uint8_t checksum; uint8_t checksum;
@@ -181,10 +171,10 @@ static bool keyboard_proto_validate_frame(const struct keyboard_cdc_CdcFrame *fr
bool keyboard_proto_try_take_cdc_frame( bool keyboard_proto_try_take_cdc_frame(
uint8_t *buffer, uint8_t *buffer,
size_t *buffer_size, size_t *buffer_size,
struct keyboard_cdc_CdcFrame *frame) keyboard_cdc_CdcFrame *frame)
{ {
for (size_t candidate_len = 1U; candidate_len <= *buffer_size; ++candidate_len) { for (size_t candidate_len = 1U; candidate_len <= *buffer_size; ++candidate_len) {
struct keyboard_cdc_CdcFrame candidate = keyboard_cdc_CdcFrame_init_zero; keyboard_cdc_CdcFrame candidate = keyboard_cdc_CdcFrame_init_zero;
pb_istream_t stream = pb_istream_from_buffer(buffer, candidate_len); pb_istream_t stream = pb_istream_from_buffer(buffer, candidate_len);
if (!pb_decode(&stream, keyboard_cdc_CdcFrame_fields, &candidate)) { if (!pb_decode(&stream, keyboard_cdc_CdcFrame_fields, &candidate)) {
@@ -206,9 +196,12 @@ bool keyboard_proto_try_take_cdc_frame(
} }
static bool keyboard_proto_build_hello_rsp_body( static bool keyboard_proto_build_hello_rsp_body(
struct keyboard_cdc_CdcPacketBody *body) keyboard_cdc_CdcPacketBody *body)
{ {
*body = keyboard_cdc_CdcPacketBody_init_zero; {
keyboard_cdc_CdcPacketBody empty = keyboard_cdc_CdcPacketBody_init_zero;
*body = empty;
}
body->which_body = KB_PROTO_BODY_TAG_HELLO_RSP; body->which_body = KB_PROTO_BODY_TAG_HELLO_RSP;
body->body.hello_rsp.protocol_version = 1U; body->body.hello_rsp.protocol_version = 1U;
body->body.hello_rsp.vendor_id = 0x1209U; body->body.hello_rsp.vendor_id = 0x1209U;
@@ -221,9 +214,12 @@ static bool keyboard_proto_build_hello_rsp_body(
static bool keyboard_proto_build_ack_body( static bool keyboard_proto_build_ack_body(
uint32_t acked_type, uint32_t acked_type,
struct keyboard_cdc_CdcPacketBody *body) keyboard_cdc_CdcPacketBody *body)
{ {
*body = keyboard_cdc_CdcPacketBody_init_zero; {
keyboard_cdc_CdcPacketBody empty = keyboard_cdc_CdcPacketBody_init_zero;
*body = empty;
}
body->which_body = KB_PROTO_BODY_TAG_ACK; body->which_body = KB_PROTO_BODY_TAG_ACK;
body->body.ack.acked_type = acked_type; body->body.ack.acked_type = acked_type;
return true; return true;
@@ -232,9 +228,12 @@ static bool keyboard_proto_build_ack_body(
static bool keyboard_proto_build_error_body( static bool keyboard_proto_build_error_body(
uint32_t error_type, uint32_t error_type,
uint32_t error_code, uint32_t error_code,
struct keyboard_cdc_CdcPacketBody *body) keyboard_cdc_CdcPacketBody *body)
{ {
*body = keyboard_cdc_CdcPacketBody_init_zero; {
keyboard_cdc_CdcPacketBody empty = keyboard_cdc_CdcPacketBody_init_zero;
*body = empty;
}
body->which_body = KB_PROTO_BODY_TAG_ERROR; body->which_body = KB_PROTO_BODY_TAG_ERROR;
body->body.error.error_type = error_type; body->body.error.error_type = error_type;
body->body.error.error_code = (keyboard_cdc_ErrorCode)error_code; body->body.error.error_code = (keyboard_cdc_ErrorCode)error_code;
@@ -244,13 +243,16 @@ static bool keyboard_proto_build_error_body(
bool keyboard_proto_build_function_key_event_body( bool keyboard_proto_build_function_key_event_body(
uint16_t usage, uint16_t usage,
bool pressed, bool pressed,
struct keyboard_cdc_CdcPacketBody *body) keyboard_cdc_CdcPacketBody *body)
{ {
if (body == NULL) { if (body == NULL) {
return false; return false;
} }
*body = keyboard_cdc_CdcPacketBody_init_zero; {
keyboard_cdc_CdcPacketBody empty = keyboard_cdc_CdcPacketBody_init_zero;
*body = empty;
}
body->which_body = KB_PROTO_BODY_TAG_FUNCTION_KEY_EVENT; body->which_body = KB_PROTO_BODY_TAG_FUNCTION_KEY_EVENT;
body->body.function_key_event.usage = usage; body->body.function_key_event.usage = usage;
body->body.function_key_event.action = pressed ? 1U : 0U; body->body.function_key_event.action = pressed ? 1U : 0U;
@@ -259,24 +261,27 @@ bool keyboard_proto_build_function_key_event_body(
bool keyboard_proto_build_led_state_body( bool keyboard_proto_build_led_state_body(
uint8_t led_mask, uint8_t led_mask,
struct keyboard_cdc_CdcPacketBody *body) keyboard_cdc_CdcPacketBody *body)
{ {
if (body == NULL) { if (body == NULL) {
return false; return false;
} }
*body = keyboard_cdc_CdcPacketBody_init_zero; {
keyboard_cdc_CdcPacketBody empty = keyboard_cdc_CdcPacketBody_init_zero;
*body = empty;
}
body->which_body = KB_PROTO_BODY_TAG_LED_STATE; body->which_body = KB_PROTO_BODY_TAG_LED_STATE;
body->body.led_state.led_mask = led_mask; body->body.led_state.led_mask = led_mask;
return true; return true;
} }
static bool keyboard_proto_handle_bitmap( static bool keyboard_proto_handle_bitmap(
const struct keyboard_cdc_CdcPacketBody *body, const keyboard_cdc_CdcPacketBody *body,
keyboard_proto_send_body_fn send_fn, keyboard_proto_send_body_fn send_fn,
void *user_data) void *user_data)
{ {
struct keyboard_cdc_CdcPacketBody response; keyboard_cdc_CdcPacketBody response;
if (body->body.bitmap.usage_bitmap.size != KEYBOARD_PROTO_FUNCTION_BITMAP_SIZE) { if (body->body.bitmap.usage_bitmap.size != KEYBOARD_PROTO_FUNCTION_BITMAP_SIZE) {
keyboard_proto_build_error_body(KB_PROTO_PACKET_BITMAP, keyboard_proto_build_error_body(KB_PROTO_PACKET_BITMAP,
@@ -292,13 +297,13 @@ static bool keyboard_proto_handle_bitmap(
} }
static bool keyboard_proto_handle_time_sync( static bool keyboard_proto_handle_time_sync(
const struct keyboard_cdc_CdcPacketBody *body, const keyboard_cdc_CdcPacketBody *body,
enum keyboard_proto_transport transport, enum keyboard_proto_transport transport,
keyboard_proto_send_body_fn send_fn, keyboard_proto_send_body_fn send_fn,
void *user_data) void *user_data)
{ {
struct time_sync_update update; struct time_sync_update update;
struct keyboard_cdc_CdcPacketBody response; keyboard_cdc_CdcPacketBody response;
if (!time_manager_is_ready()) { if (!time_manager_is_ready()) {
keyboard_proto_build_error_body(KB_PROTO_PACKET_TIME_SYNC, keyboard_proto_build_error_body(KB_PROTO_PACKET_TIME_SYNC,
@@ -326,11 +331,11 @@ static bool keyboard_proto_handle_time_sync(
} }
static bool keyboard_proto_handle_theme_rgb( static bool keyboard_proto_handle_theme_rgb(
const struct keyboard_cdc_CdcPacketBody *body, const keyboard_cdc_CdcPacketBody *body,
keyboard_proto_send_body_fn send_fn, keyboard_proto_send_body_fn send_fn,
void *user_data) void *user_data)
{ {
struct keyboard_cdc_CdcPacketBody response; keyboard_cdc_CdcPacketBody response;
display_theme_event_submit((uint8_t)body->body.theme_rgb.red, display_theme_event_submit((uint8_t)body->body.theme_rgb.red,
(uint8_t)body->body.theme_rgb.green, (uint8_t)body->body.theme_rgb.green,
@@ -341,12 +346,12 @@ static bool keyboard_proto_handle_theme_rgb(
} }
bool keyboard_proto_handle_host_body( bool keyboard_proto_handle_host_body(
const struct keyboard_cdc_CdcPacketBody *body, const keyboard_cdc_CdcPacketBody *body,
enum keyboard_proto_transport transport, enum keyboard_proto_transport transport,
keyboard_proto_send_body_fn send_fn, keyboard_proto_send_body_fn send_fn,
void *user_data) void *user_data)
{ {
struct keyboard_cdc_CdcPacketBody response; keyboard_cdc_CdcPacketBody response;
if ((body == NULL) || (send_fn == NULL)) { if ((body == NULL) || (send_fn == NULL)) {
return false; return false;

View File

@@ -32,7 +32,7 @@ static struct usb_cdc_proto_ctx g_usb_cdc = {
}; };
static uint32_t keyboard_proto_packet_type_from_body( static uint32_t keyboard_proto_packet_type_from_body(
const struct keyboard_cdc_CdcPacketBody *body) const keyboard_cdc_CdcPacketBody *body)
{ {
switch (body->which_body) { switch (body->which_body) {
case 1U: case 1U:
@@ -59,7 +59,7 @@ static uint32_t keyboard_proto_packet_type_from_body(
} }
static bool usb_cdc_proto_send_body( static bool usb_cdc_proto_send_body(
const struct keyboard_cdc_CdcPacketBody *body, const keyboard_cdc_CdcPacketBody *body,
void *user_data) void *user_data)
{ {
struct usb_cdc_proto_ctx *ctx = user_data; struct usb_cdc_proto_ctx *ctx = user_data;
@@ -88,8 +88,8 @@ static bool usb_cdc_proto_send_body(
static void usb_cdc_proto_process_rx_work(struct k_work *work) static void usb_cdc_proto_process_rx_work(struct k_work *work)
{ {
struct keyboard_cdc_CdcFrame frame; keyboard_cdc_CdcFrame frame;
struct keyboard_cdc_CdcPacketBody body; keyboard_cdc_CdcPacketBody body;
ARG_UNUSED(work); ARG_UNUSED(work);
@@ -162,7 +162,7 @@ static bool handle_module_state_event(const struct module_state_event *event)
static bool handle_function_key_event(const struct function_key_event *event) static bool handle_function_key_event(const struct function_key_event *event)
{ {
struct keyboard_cdc_CdcPacketBody body; keyboard_cdc_CdcPacketBody body;
if (!g_usb_cdc.ready) { if (!g_usb_cdc.ready) {
return false; return false;
@@ -180,7 +180,7 @@ static bool handle_function_key_event(const struct function_key_event *event)
static bool handle_keyboard_led_event(const struct keyboard_led_event *event) static bool handle_keyboard_led_event(const struct keyboard_led_event *event)
{ {
struct keyboard_cdc_CdcPacketBody body; keyboard_cdc_CdcPacketBody body;
if (!g_usb_cdc.ready) { if (!g_usb_cdc.ready) {
return false; return false;