Solution: Multimode Keyboard¶
重要
此例程仅存在于特殊版本的SDK中,如有需要请联系Panchip。
1 功能概述¶
此sample为pan108xxb5
(64pin芯片)在实体键盘板下的应用
具体支持的feature如下:
通用功能:
按键模块:支持75%的配列布局,支持标准按键/无冲按键
多层按键映射:目前默认添加FN 层,实现F1 - F12多媒体按键,以及用户自定义事件,可扩展其它层。
QDEC滚轮模块:支持去抖的正交解码器,正反转实现快速音量大小调节
LED模块:键盘右上角从上到下四个LED分别为CAPS LOCK/USB/2.4G/BLE指示灯,分别指示各模式下的连接状态
电量检测:ADC采集电量信息,低电量时默认左上角第一个LED(ESC键底部)红色闪烁
供电及模式切换:
a. 电池供电:底部按键可以切换2.4G模式与蓝牙模式,开关拨到中间中间为断电状态
b. USB仅供电:底部按键可以切换2.4G模式与蓝牙模式,中间为USB模式
2.4G模式(PRF增强型模式)
跳频:在信号质量不好(连续
FREQ_HOP_NOACK_THREHOLD
=15个ack未收到)/对码前在8个频点进行跳频对码:上电跳频找到dongle端的频点后,通信互发对端的MAC地址后2字节,之后切换到私有地址进行通信
重传:丢包时会进行重传,以最快速度进行重传直到收到对端回复
ACK:可解析的ACK,具有演示代码
性能:默认上报率1000的情况下,近距离稳定在990包以上,8-9米稳定在960包以上
测试模式(可选):宏控制自动画圈(需要在
prj.conf
文件中设置宏定义CONFIG_TEST_REPORT_RATE=y
,键盘按FN + 8
)
BLE模式
蓝牙白名单,分时连接
配对,保存
连接,重连功能:
OTA(未使能):与mcuboot配合通过NRF工具进行升级
性能:133HZ上报率
性能:兼容性
USB模式
性能:USB2.0最高速率1000hz
电脑的休眠唤醒(未做)
升级:与mcuboot配合通过USB工具进行升级
EMI测试
2 环境要求¶
board:
pan108xxb5
(芯片型号)键盘板USB升级工具(USB升级工具获取:https://docs.panchip.com/pan1080dk-doc/latest/docs-zdk/06_dev_tools/pan108x_toolbox_intro.html)
鼠标测试工具:
KEYTEST.exe
3 编译和烧录¶
例程位置:zephyr\samples_panchip\solutions\multimode_keyboard
使用 ZAL 工具可以对其进行编译、烧录、打开 VS Code 调试等操作。关于 ZAL 工具的详细介绍请参考:Zephyr APP Launcher 工具介绍。
4 演示说明¶
芯片全部擦除还原默认状态,准备好烧录multimode_keyboard_dongle
的接收器
4.1 电池供电模式¶
硬件支持锂电池供电
1、电池供电模式下3.6V低压报警(键盘左上角第一个RGB红色快闪),3.4V进入休眠状态,在不同的灯效下可能会提前进入低压报警状态
2、电池供电模式下,无任何按键按下的情况下,30S后关闭RGB灯光,2.4G模式60S后进入休眠,BLE模式保持连接状态,10分钟后进入休眠
4.2 USB供电模式¶
USB供电后,键盘不进入休眠状态
4.3 模式切换说明¶
2.4G模式:将键盘背部的拨动开关向左拨,键盘进入2.4G模式,如果键盘处于配对状态,键盘对应的2.4G指示灯快闪,此时插入dongle,键盘对应的2.4G指示灯常亮,代表键盘连接成功。拔掉dongle,指示灯慢闪,说明键盘处于断连状态。处于2.4G模式时,任意时刻可通过长按
FN
+4
3秒,让键盘进入强制配对状态。BLE模式:将键盘背部的拨动开关向右拨,键盘进入BLE模式,如果键盘处于配对状态,键盘对应的BLE指示灯快闪,电脑端弹出名称为keyboard[0/1/2]的设备,连接成功后,指示灯长亮。如果键盘处于断连状态,指示灯慢闪。
键盘处于BLE模式时,通过短按
FN
+1
切换到1通道,通过短按FN
+2
切换到2通道,通过短按FN
+3
切换到3通道。在任一通道上,通过长按FN
+通道号
3秒进入强制配对状态。USB模式:将键盘背部的拨动开关拨到中间,插入USB线,键盘进入USB模式,键盘对应的USB指示灯亮起。
4.4 测试模式¶
4.4.1 组合按键测试¶
组合按键说明
组合键 |
基础键 |
功能 |
---|---|---|
FN |
F1 |
我的电脑(多媒体快捷键) |
FN |
F2 |
主页(多媒体快捷键) |
FN |
F3 |
计算器(多媒体快捷键) |
FN |
F4 |
多媒体(多媒体快捷键) |
FN |
F5 |
上一曲(多媒体快捷键) |
FN |
F6 |
下一曲(多媒体快捷键) |
FN |
F7 |
暂停/播放(多媒体快捷键) |
FN |
F8 |
停止(多媒体快捷键) |
FN |
F9 |
静音(多媒体快捷键) |
FN |
F10 |
音量降低(多媒体快捷键) |
FN |
F11 |
音量提高(多媒体快捷键) |
FN |
F12 |
邮件(多媒体快捷键) |
FN |
空格键 |
打开/关闭RGB背光 |
FN |
↑ |
背光亮度提高 |
FN |
↓ |
背光亮度降低 |
FN |
← |
灯光速度减缓(暂未添加) |
FN |
→ |
灯光速度加快(暂未添加) |
FN |
1 |
蓝牙模式下短按切换蓝牙通道1,长按3秒进入配对 |
FN |
2 |
蓝牙模式下短按切换蓝牙通道2,长按3秒进入配对 |
FN |
3 |
蓝牙模式下短按切换蓝牙通道3,长按3秒进入配对 |
FN |
4 |
2.4G模式下长按3秒进入配对 |
FN |
5 |
任意模式下长按3秒进入EMI测试模式(暂未添加) |
FN |
6 |
EMI模式下短按切换测试模式 |
FN |
7 |
EMI模式下短按切换测试频点 |
FN |
8 |
上报率测试打开/关闭(模拟鼠标画圈) |
4.5 USB升级(DFU)¶
USB DFU 升级操作可以参考 05_TOOLS\量产烧录工具\Panchip DFU Tool
最新版本的帮助内容内的操作说明,以下说明升级需要注意的点及原理
关于boot的文档可以参考https://docs.panchip.com/pan1080dk-doc/latest/docs-zdk/04_dev_guides/zephyr_bootloader_guidance.html
4.5.1 升级原理¶
SDK 1.0.2 之前的版本,升级通过App程序区的USB EP3端点进行消息交互,联同上位机进行升级流程,可以升级鼠标和dongle程序,但是需要注意识别过程需要正确写入芯片VID PID扫描到已有设备,为保证升级兼容性,rebuild编译后的工程强烈建议app区和controller区同时升级,并且先进行app升级再进行controller升级
SDK 1.0.2 包括之后的版本,灵活开放了boot区的编译,并默认提供了一种方式,程序区先写入flash flag确保进入强制升级,未退出强制升级之前,芯片重新上电始终会停留在boot区域,确认好固件正确性后可以退出强制升级
SDK 1.1.0 包括之后的版本,编译了两种特殊mcuboot固件(存放于01_SDK\modules\hal\panchip\panplat\pan1080\bootloader
),支持boot内DFU升级
bootdfu_for_mouse:支持xxa1编译所有鼠标工程及键盘dongle工程,支持boot内usb升级,支持boot内4k dongle或者8k鼠标的spi透传升级
bootdfu_for_keyboard:支持xxb1编译的keyboard工程,支持boot内usb升级
通过应用层宏CONFIG_MCUBOOT_IMAGE_TYPE
可以直接控制编译链接的特殊mcuboot固件,值对应上述固件类型
4.5.2 boot自定义编译说明¶
如果需要自定义更新mcuboot固件,需要注意以下对应关系,建议操作步骤如下
编译mcuboot,注意控制好相关的宏(CONFIG_MCUBOOT_PAN_USB_DFU
或者CONFIG_MCUBOOT_PAN_USB_SPI
)开启及编译board的选择
以自定义编译键盘固件为例
ZAL工具编译mcuboot工程,编译board选择xxb1,提前修改01_SDK\bootloader\mcuboot\boot\zephyr\prj,conf
内的宏,之后进行编译,编译后的mcuboot固件会自动替换原有的默认mcuboot固件(不包含任何升级功能)01_SDK\modules\hal\panchip\panplat\pan1080\bootloader\images
此时如果需要使用此编译固件,可以将APP工程内的CONFIG_MCUBOOT_IMAGE_TYPE
宏屏蔽,使用默认的值即会使用被替换掉的mcuboot(也可以灵活处理保存到特殊文件夹通过扩展宏自己控制)
4.5.3 注意事项¶
使用具有保护功能的boot时,boot的VID为0x046D,PID为0xC055,usb name 为 boot dfu
通过上位机工具量产烧录工具\Panchip DFU Tool
升级时,可以参考工具内文档说明的步骤进行升级,注意选择支持强制升级的版本
PS
程序run在boot区时,点击重启芯片
可以跳转到app区域,程序升级正常之前,重新上电即可继续升级正确固件
4.6 DeviceTool使用¶
配合上位机工具键鼠专用工具\PAN108x工具\MouseDeviceTool
可以进行产线USB信息测试及单载波测试,具体操作可以参考工具内说明文档
默认界面支持自定义消息开发
显示界面可以切换到USB设置测试
功能界面
5 开发说明¶
5.1 架构说明¶
multimode_keyboard
基于zephyr架构,进行多线程编程,线程静态初始化后,根据优先级进行先后初始化,之后各个线程运行至while(1)等待相应的信号量,以此通过控制信号量控制各个线程的调度关系
架构中应用层主要包含
8个线程
MAIN
电量检测
EMI测试
按键扫描
跳频
RF发包
USB发包
BLE发包
上报率测试(默认关闭)
4个中断
TIMER0中断(触发组包)
TIMER1中断(255us周期,灯效值处理,按键端口状态扫描)
USB中断
PRF中断
3个重要接口
BLE接口(Zephyr API):FRAME组包后通过调用蓝牙接口进入HOST层进行发包,非阻塞接口,会为ble host填充最多6包数据
/** @brief Notify attribute value change no wait. * * Send notification of attribute value change, if connection is NULL notify * all peer that have notification enabled via CCC otherwise do a direct * notification only the given connection. * * The attribute object on the parameters can be the so called Characteristic * Declaration, which is usually declared with BT_GATT_CHARACTERISTIC followed * by BT_GATT_CCC, or the Characteristic Value Declaration which is * automatically created after the Characteristic Declaration when using * BT_GATT_CHARACTERISTIC. * * @param conn Connection object. * @param attr Characteristic or Characteristic Value attribute. * @param data Pointer to Attribute data. * @param len Attribute value length. * * @return 0 in case of success or negative value in case of error. */ static inline int bt_gatt_notify_no_wait(struct bt_conn *conn, const struct bt_gatt_attr *attr, const void *data, uint16_t len)
USB EP3接口(VENDOR DFU):通过USB中断进入进行DFU升级,EMI测试
void usb_vendor_ep3_out(void)
低功耗接口
应用进入低功耗宏(长时间静止后进入Deepsleep)
CONFIG_PM_MOUSE=y
系统空闲进入Deepsleep宏,注意程序默认开启了
CONFIG_PM=y
,如果不用系统Deepsleep,需要以下四个宏一起屏蔽,蓝牙模式下生效开启 系统空闲进入Deepsleep 模式 ### open CONFIG_PM ### CONFIG_PM=y CONFIG_BT_CTLR_SLEEP_CLOCK_SOURCE=1 #Accuracy is 2000ppm CONFIG_BT_CTLR_SLEEP_TIMER_ACCURACY=2000 #Enable RCL Force CALIBRATION CONFIG_SOC_FORCE_CALIB_RCL_CLK=y ### open CONFIG_PM ### 关闭 系统空闲进入Deepsleep 模式 ### not open CONFIG_PM ### # CONFIG_PM=y # CONFIG_BT_CTLR_SLEEP_CLOCK_SOURCE=1 # #Accuracy is 2000ppm # CONFIG_BT_CTLR_SLEEP_TIMER_ACCURACY=2000 # #Enable RCL Force CALIBRATION # CONFIG_SOC_FORCE_CALIB_RCL_CLK=y ### not open CONFIG_PM ###
5.2 线程说明¶
线程定义方式如下,选用静态线程的方式,由于包含多种reboot操作,实际单模式生效可对其他无用线程进行中止操作,线程之间通过信号量进行切换或者挂起
/**
* @brief Statically define and initialize a thread.
*
* The thread may be scheduled for immediate execution or a delayed start.
*
* Thread options are architecture-specific, and can include K_ESSENTIAL,
* K_FP_REGS, and K_SSE_REGS. Multiple options may be specified by separating
* them using "|" (the logical OR operator).
*
* The ID of the thread can be accessed using:
*
* @code extern const k_tid_t <name>; @endcode
*
* @param name Name of the thread.
* @param stack_size Stack size in bytes.
* @param entry Thread entry function.
* @param p1 1st entry point parameter.
* @param p2 2nd entry point parameter.
* @param p3 3rd entry point parameter.
* @param prio Thread priority.
* @param options Thread options.
* @param delay Scheduling delay (in milliseconds), zero for no delay.
*
*
* @internal It has been observed that the x86 compiler by default aligns
* these _static_thread_data structures to 32-byte boundaries, thereby
* wasting space. To work around this, force a 4-byte alignment.
*
*/
#define K_THREAD_DEFINE(name, stack_size, \
entry, p1, p2, p3, \
prio, options, delay) \
K_THREAD_STACK_DEFINE(_k_thread_stack_##name, stack_size); \
struct k_thread _k_thread_obj_##name; \
STRUCT_SECTION_ITERABLE(_static_thread_data, _k_thread_data_##name) = \
Z_THREAD_INITIALIZER(&_k_thread_obj_##name, \
_k_thread_stack_##name, stack_size, \
entry, p1, p2, p3, prio, options, delay, \
NULL, name); \
const k_tid_t name = (k_tid_t)&_k_thread_obj_##name
根据线程定义,定义了如下几个线程,并在common.h
统一管理线程优先级及栈大小
#define BATTERY_THREAD_PRIORITY 7
#define BATTERY_THREAD_STACKSIZE 768
#define BLE_THREAD_PRIORITY 3
#define BLE_THREAD_STACKSIZE 1024
#define EMI_THREAD_PRIORITY 2
#define EMI_THREAD_STACKSIZE 512
#define KEY_SCAN_THREAD_PRIORITY 1
#define KEY_SCAN_THREAD_STACKSIZE 1024
#define FREQ_HOP_THREAD_PRIORITY 2
#define FREQ_HOP_THREAD_STACKSIZE 512
#define PRF_THREAD_PRIORITY 1
#define PRF_THREAD_STACKSIZE 512
#define TEST_REPORT_RATE_THREAD_PRIORITY 2
#define TEST_REPORT_RATE_THREAD_STACKSIZE 512
#define USB_THREAD_PRIORITY 2
#define USB_THREAD_STACKSIZE 512
5.2.1 BATTERY线程¶
电量监测线程,ADC_SCAN_INTERVAL_MS = 100 ms的间隔进行电量采集,判断电池低压情况,以及判断是否有模式发生切换。并同时进行WDT喂狗,蓝牙模式进行电量进行上报
5.2.2 MAIN线程¶
主线程,处理软件和硬件的初始化工作,例如GPIO/ADC/PWM/TIMER/QDEC等,进行工作模式检测,如果是2.4G模式,并且未配对,则进行配对处理
5.2.3 FREQ_HOP线程¶
跳频线程,初始化对码线程会触发进入,在收到ACK少的时候会触发,通过信号量与PRF线程存在互斥关系
5.2.4 PRF线程¶
2.4G主线程,会进行重传处理,在重传条件下收到ACK数量低于阈值进入跳频线程
5.2.5 USB线程¶
USB线程,USB插入PC时进入,获取组包并且上报
5.2.6 BLE线程¶
BLE线程,获取数据包进行上报
5.2.7 EMI线程¶
通过TIMER0触发EMI测试中发包相关逻辑
5.2.8 KEY线程¶
按键事件处理(基础按键组包,组合按键处理),在按键全部松开的时候,判断是否进入低功耗
5.2.9 TEST_REPORT线程(上报率测试线程,默认关闭)¶
模拟鼠标自动画圈,用于测试上报率,默认关闭
5.3 RF中断说明¶
5.3.1 RF中断¶
鼠标端为PRF TX端,增强型模式会在TX后自动转入RX, 中断中主要处理信号量sem_prf_isr
的给出及ack_lost_cnt
的计数
5.3.2 TIMER0中断¶
TIMER中断产生多线程的控制信号量,并且根据不同上报率切换timer中断间隔
5.3.3 TIMER1中断¶
TIMER1中断用来控制LED灯显示,每一次中断后点亮键盘矩阵中某一列的灯,灯的状态发生变化后在中断中刷新对应的buff数值。按键端口变化值在中断中获取,扫描完端口的变化后,释放按键处理信号量,在按键线程中完成键值的组包和处理。
5.4 主要数据结构说明¶
5.4.1 枚举状态¶
5.4.1.1 配对状态¶
enum prf_pair_stat_t {
prf_pair_start,
prf_pair_comm,
prf_pair_addr,
prf_pair_end,
prf_paired_private,
prf_paired_public,
};
5.4.1.2.连接状态¶
enum ble_connect_stat_t {
ble_disconnect_stat,
ble_connect_stat,
};
5.4.1.3 工作模式¶
enum keyboard_work_mode_t {
keyboard_null_mode,
keyboard_usb_mode,
keyboard_prf_mode,
keyboard_ble_mode,
};
5.4.1.4 2.4G RF状态¶
enum prf_trx_stat_t {
prf_idle_stat,
prf_tx_done_stat,
prf_rx_done_stat,
prf_rx_timeout_stat,
prf_rx_crc_err_stat,
prf_rx_pid_err_stat,
};
5.4.1.5 跳频状态¶
enum prf_freq_hop_stat_t {
freq_hop_disconnect_stat,
freq_hop_connecting_stat,
freq_hop_done_stat,
};
5.4.1.6 USB状态¶
enum usb_plug_mode_t {
usb_plug_in,
usb_plug_out,
};
5.4.1.7 灯状态¶
enum keyboard_led_stat_t {
led_unpair_stat,
led_paired_stat,
led_low_batt_stat,
led_prf_connected,
led_prf_disconnected,
led_key_stat,
led_usb_stat,
led_ble_connected_stat,
led_ble_disconnected_stat,
led_ble_pairing_stat,
led_emi_stat,
};
5.4.1.8 休眠唤醒低功耗状态¶
enum keyboard_low_power_stat_t {
active_stat,
prf_off_stat,
deep_sleep_v1_stat,
deep_sleep_v2_stat,
standby_stat,
};
5.4.2 全局结构¶
5.4.2.1 组包ring_buf(zephyr)¶
/**
* @brief A structure to represent a ring buffer
*/
struct ring_buf {
uint32_t head; /**< Index in buf for the head element */
uint32_t tail; /**< Index in buf for the tail element */
union ring_buf_misc {
struct ring_buf_misc_item_mode {
uint32_t dropped_put_count; /**< Running tally of the
* number of failed put
* attempts.
*/
} item_mode;
struct ring_buf_misc_byte_mode {
uint32_t tmp_tail;
uint32_t tmp_head;
} byte_mode;
} misc;
uint32_t size; /**< Size of buf in 32-bit chunks */
union ring_buf_buffer {
uint32_t *buf32; /**< Memory region for stored entries */
uint8_t *buf8;
} buf;
uint32_t mask; /**< Modulo mask if size is a power of 2 */
struct k_spinlock lock;
};
5.4.2.2 packet格式结构体¶
键盘发送的2.4G帧格式如下
前导码 |
接入地址 |
signal |
payload |
crc |
---|---|---|---|---|
3B |
4B |
10bit |
3/24B |
2B |
0x550f71 |
公共地址/私有地址 |
增强型的字段 |
跳频对码包/键盘数据包 |
16bit crc |
其中键盘Payload为用户可以修改的数据段,Payload中又包含了3个字节的固定数据,其中3个字节的固定数据格式如下
Type |
Addr |
---|---|
1B |
2B |
包的类型:对码跳频包/键盘数据包 |
己端MAC地址后两个字节 |
Type定义如下
#define PRF_PKT_TYPE_PAIR (1 << 0)
#define PRF_PKT_TYPE_FREQ_HOP (1 << 1)
#define PRF_PKT_TYPE_KEYBOARD_DATA (1 << 2)
#define PRF_PKT_TYPE_LED_STATUS (1 << 3)
跳频对码包:
header: PRF_PKT_TYPE_FREQ_HOP | PRF_PKT_TYPE_PAIR
跳频包:
header: PRF_PKT_TYPE_FREQ_HOP
数据包:
header: PRF_PKT_TYPE_KEYBOARD_DATA
键盘LED状态包:
header: PRF_PKT_TYPE_LED_STATUS
键盘LED状态包用于2.4G dongle端回发CAPS LOCK/NUM LOCK/SCROLL LOCK状态
另外包含21个字节应用层数据(ringbuf管理的数据结构)
key_type |
key_value |
header |
sequence |
rate_pkt_index |
reserved |
---|---|---|---|---|---|
1B |
16B |
1B |
1B |
1B |
1B |
键值类型 |
按键值 |
包头 |
序列号 |
上报率 |
保留扩展位 |
#define KEYBOARD_KEY_SIZE 16
struct keyboard_pkt_detect_t {
uint8_t key_event;
uint8_t key_value[KEYBOARD_KEY_SIZE];
uint8_t header;
uint8_t sequence;
uint8_t rate_pkt_index;
uint8_t reserved;
};
在dongle端根据key_type类型,对key_value数据进行解析,其中包含5中键值类型:
5.4.2.3 标准按键格式结构体¶
#define KEYBOARD_STANDARD_KEY_SIZE 8
typedef union {
uint8_t buff[KEYBOARD_STANDARD_KEY_SIZE];
struct {
union {
uint8_t specialKey;
struct {
uint8_t LCtrl : 1;
uint8_t LShift : 1;
uint8_t LAlt : 1;
uint8_t LGUI : 1;
uint8_t RCtrl : 1;
uint8_t RShift : 1;
uint8_t RAlt : 1;
uint8_t RGUI : 1;
};
};
uint8_t reserve;
uint8_t code[6];
};
} standard_report_s;
5.4.2.4 无冲按键格式结构体¶
#define KEYBOARD_BIT_KB_KEY_SIZE 16
typedef union {
uint8_t buff[KEYBOARD_BIT_KB_KEY_SIZE];
struct {
uint8_t id;
uint8_t code[15];
};
} bit_kb_key_report_s;
5.4.2.5 媒体按键格式结构体¶
#define KEYBOARD_MEDIA_KEY_SIZE 3
typedef union {
uint8_t buff[KEYBOARD_MEDIA_KEY_SIZE];
struct {
uint8_t id;
uint8_t code[2];
};
} media_key_report_s;
5.4.2.6 电源按键格式结构体¶
#define KEYBOARD_POWER_KEY_SIZE 2
typedef union {
uint8_t buff[KEYBOARD_POWER_KEY_SIZE];
struct {
uint8_t id;
union {
uint8_t flag;
struct {
uint8_t shutdown : 1;
uint8_t sleep : 1;
uint8_t wakeup : 1;
uint8_t reserve : 5;
};
};
};
} power_key_report_s;
5.4.2.7 鼠标按键格式结构体¶
#define KEYBOARD_MOUSE_SIZE 8
typedef union {
uint8_t buff[KEYBOARD_MOUSE_SIZE];
struct {
uint8_t id;
union {
uint8_t key_value;
struct {
uint8_t LeftBtn : 1;
uint8_t RightBtn : 1;
uint8_t MidBtn : 1;
uint8_t BackBtn : 1;
uint8_t ForwardBtn : 1;
uint8_t reserve : 3;
};
};
int16_t x_value;
int16_t y_value;
int8_t roll_value;
int8_t tilt_roll_value;
};
} mouse_report_s;
键盘接收的2.4G ACK数据帧格式如下
前导码 |
接入地址 |
signal |
payload |
crc |
---|---|---|---|---|
3B |
4B |
10bit |
xB |
2B |
0x550f71 |
公共地址/私有地址 |
增强 |
ACK数据(长度自定义,默认数据长度为0) |
16bit crc |
用户可以根据需求扩展使用ACK数据
dongle回传LED状态信息数据帧格式如下
前导码 |
接入地址 |
signal |
payload[0] |
payload[1] |
crc |
---|---|---|---|---|---|
3B |
4B |
10bit |
1B |
1B |
2B |
0x550f71 |
公共地址/私有地址 |
增强 |
LED指示灯类型 |
LED指示灯值 |
16bit crc |
5.4.2.8 收包计数结构体¶
struct prf_pkt_cnt_t {
uint32_t tx_cnt;
uint32_t rx_cnt;
uint8_t prf_repeat_cnt;
};
5.4.2.9 配对信息结构体¶
struct pair_ctrl_t {
enum prf_pair_stat_t prf_pair_stat;
uint32_t prf_pair_timeout;
uint8_t pair_own_addr[2];
uint8_t pair_peer_addr[2];
bool paired_flag;
};
5.5 主要逻辑图示¶
5.6 键鼠套件(附)¶
键鼠套件由PAN1080做主设备,可能是鼠标(1000hz),大键盘(125hz),小键盘(125hz)
需要配合配套键盘及配套2628dongle(支持多pipe)使用,PAN2628参考固件及烧录工具可以从05_TOOLS\键鼠专用工具\第三方工具\PAN2628固件工具
获取,源码可联系我司获取
键盘作为键鼠套件时,需要在commom.c
中使能
#define KB_MOUSE_ONEDONLE 1
5.6.1 配对过程¶
6.1.1 配对参数¶
鼠标采用公共地址:0x7B, 0x41, 0x29, 0x79
大键盘采用公共地址:0x7C, 0x41, 0x29, 0x79
小键盘采用公共地址:0x7D, 0x41, 0x29, 0x79
公共频点为:
u8 idata channel_list_public[8] =
{
4, 12, 18, 30, 38, 44, 56, 74
};
dongle采用多pipe模式进行接收:
pipe0接收地址(鼠标):0x7B, 0x41, 0x29, 0x79
pipe1接收地址(大键盘):0x7C, 0x41, 0x29, 0x79
pipe2接收地址(小键盘):0x7D, 0x41, 0x29, 0x79
经以上配置后:
dongle从pipe0接收的数据认为是鼠标数据
dongle从pipe1接收的数据认为是大键盘数据
dongle从pipe2接收的数据认为是小键盘数据
5.6.1.2 配对时序¶
dongle上电后,配置完RF参数,再依次开启pipe0~pipe2开始接收公共地址的配对信息,dongle根据pipe号来区分是哪个设备发来的配对命令。 以mouse配对为例,mouse上电后,配置完RF参数后,设置RF地址为0x7B, 0x41, 0x29, 0x79,即鼠标的专用配对地址,并以channel_list_public为跳频地址表。之后mouse会发送配对请求包,请求包的格式为:
magic[4B] |
命令[1B] |
地址[6B] |
---|---|---|
0x31415926 |
0x01 |
mouse mac |
dongle收到mouse的配对请求包后:
如果收到的配对请求命令不正确,则不回复任务消息。
如果配对请求命令校验正确无误,则回复以下响应:
magic[4B] |
命令[1B] |
地址[6B] |
---|---|---|
0x31415926 |
0x01 |
dongle mac |
dongle收到正确的配对请求后,会将mouse的mac地址写入flash保存下来。
mouse收到dongle配对响应后,核对正确后,会将dongle的地址写入flash保存下来。
mouse写完dongle的mac地址后,会再次发送配对的检查命令,用于检查dongle端是否正确保存mouse的配对信息,命令格式如下:
magic[4B] |
命令[1B] |
---|---|
0x31415926 |
0x02 |
dongle端收到mouse的检查命令后,如果命令核对不正确,则不回复任何消息。
如果命令核对正确,则回复以下消息:
magic[4B] |
命令[1B] |
地址[6B] |
---|---|---|
0x31415926 |
0x02 |
mouse mac |
mouse端收到dongle的回复后,核对dongle地址无误后,则认为mouse配对过程结束,否则重新开始发送配对请求包,重新以上配对过程,直到配对成功。
以上配对流程总结如下图:
5.6.1.3 配对时间说明¶
dongle上电后,最长配对时间不超过20秒(当前配对时间窗口为3秒)
如果mouse,keyboard都快速配对完成,则dongle不需要等待超时时间到达,提前进入通信流程
5.6.2 数据通信过程¶
5.6.2.1 私有地址¶
dongle Vs mouse:使用pipe0管道,采用mouse mac[5]和dongle mac[3]~mac[5]组成一个4字节的地址作为通信地址
dongle Vs 大键盘:使用pipe1管道,采用大键盘mac[5]和dongle mac[3]~mac[5]组成一个4字节的地址作为通信地址
dongle Vs 小键盘:使用pipe2管道,采用小键盘mac[5]和dongle mac[3]~mac[5]组成一个4字节的地址作为通信地址
5.6.2.2 跳频通道¶
根据dongle地址各自计算私有跳频列表,之后按私有跳频列表来进行跳频通信,跳频方式和之前相同。
5.6.2.3 跳频规则¶
dongle 若10ms内没有收到数据,则产生跳频,规则是切换至下一频道上监听10ms,10ms内没有收到数据,再切换至下一频道继续监听,直到在某个频道到收到数据包,则停止跳频,开始进行数据通信。
设备(mouse,keyboard etc)若连续10包发送不成功,则产生跳频,规则是切换至下一频道并发送数据包,若没有收到ack,再切换至下一频道继续发送数据,直到收到ack,停止跳频。
5.6.2.4 超时时间¶
以鼠标为例,当鼠标配对完成后,进入数据通信模式,此时dongle可能因为大小键盘还没有完成配对,因此鼠标要设置一个最大数据发送超时时间T0,超出这个时间鼠标还不能进行正常数据通信,鼠标则要进入休眠模式,直到用户唤醒鼠标。
假如dongle设定的最长配对时间T1为5秒,则保证T1大于T0,量化下来T0 = T1 +1秒。
5.6.3 数据格式¶
5.6.3.1 通信包¶
键盘发送的2.4G帧格式如下
前导码 |
接入地址 |
signal |
payload |
crc |
---|---|---|---|---|
3B |
4B |
10bit |
24B |
2B |
0x550f71 |
固定的 |
增强型的字段 |
跳频对码包/键盘数据包 |
16bit crc |
其中鼠标Payload为用户可以修改的数据段,Payload中又包含了3个字节的固定数据,其中3个字节的固定数据格式如下
Type |
Addr |
---|---|
1B |
2B |
包的类型:对码跳频包/鼠标包 |
己端MAC地址后两个字节 |
Type定义如下
#define PRF_PKT_TYPE_PAIR (1 << 0)
#define PRF_PKT_TYPE_FREQ_HOP (1 << 1)
#define PRF_PKT_TYPE_KEYBOARD_DATA (1 << 2)
#define PRF_PKT_TYPE_LED_STATUS (1 << 3)
跳频对码包:
header: PRF_PKT_TYPE_FREQ_HOP | PRF_PKT_TYPE_PAIR
跳频包:
header: PRF_PKT_TYPE_FREQ_HOP
数据包:
header: PRF_PKT_TYPE_KEYBOARD_DATA
键盘LED状态包:
header: PRF_PKT_TYPE_LED_STATUS
键盘LED状态包用于2.4G dongle端回发CAPS LOCK/NUM LOCK/SCROLL LOCK状态
另外包含21个字节应用层数据(ringbuf管理的数据结构)
key_type |
key_value |
header |
sequence |
rate_pkt_index |
reserved |
---|---|---|---|---|---|
1B |
16B |
1B |
1B |
1B |
1B |
键值类型 |
按键值 |
包头 |
序列号 |
上报率 |
保留扩展位 |
#define KEYBOARD_KEY_SIZE 16
struct keyboard_pkt_detect_t {
uint8_t sequence;
uint8_t header;
key_type_s key_type;
uint8_t key_value[KEYBOARD_KEY_SIZE];
uint8_t rate_pkt_index;
uint8_t reserved;
} __packed;
键盘接收的2.4G ACK数据帧格式如下
前导码 |
接入地址 |
signal |
payload |
crc |
---|---|---|---|---|
3B |
5B |
10bit |
xB |
2B |
0x550f71 |
固定的 |
增强 |
ACK数据(长度自定义,默认数据长度为0) |
16bit crc |
用户可以根据需求扩展使用ACK数据
dongle回传LED状态信息数据帧格式如下
前导码 |
接入地址 |
signal |
payload[0] |
payload[1] |
crc |
---|---|---|---|---|---|
3B |
4B |
10bit |
1B |
1B |
2B |
0x550f71 |
公共地址/私有地址 |
增强 |
LED指示灯类型 |
LED指示灯值 |
16bit crc |
5.6.4 操作说明¶
PAN2628dongle配套的固件及烧录工具说明可以从05_TOOLS\键鼠专用工具\第三方工具\PAN2628固件工具
获取烧录
PAN2628源码部分可以联系我司获取
5.6.4.1 1080键盘代码宏定义键鼠套件 鼠标/键盘 说明¶
#define KB_MOUSE_ONEDONLE 0
#if KB_MOUSE_ONEDONLE
#define PAIR_MAGIC 0x31415926
struct pkt_pair_t {
uint32_t magic;
uint8_t cmd;
uint8_t mac[6];
} __packed;
struct pkt_pair_ack_t {
uint32_t magic;
uint8_t cmd;
uint8_t mac[6];
} __packed;
#define PRF_PUBLIC_ADDR { 0x7c, 0x41, 0x29, 0x79 }
#else
#define PRF_PUBLIC_ADDR { 0x7b, 0x41, 0x29, 0x71 }
#endif
KB_MOUSE_ONEDONLE
:
默认值为0代表原始单键盘套件,配对逻辑未修改,使用默认配对地址
{ 0x7b, 0x41, 0x29, 0x71 }
设置为1代表 键鼠套件125hz鼠标,配对逻辑已更新(可以通过此宏定义查看配对逻辑差异),使用默认配对地址
{ 0x7c, 0x41, 0x29, 0x79 }
5.6.4.2 操作步骤¶
准备好2628dongle固件,烧录工程
combo_usb_dongle
固件,具有mac地址的使用MAC地址完成配对,否则使用默认值进行配对。准备2块鼠标板,一块烧录 键鼠套件鼠标A,一块烧录 键鼠套件键盘B
A和B同时进入配对快闪状态,复位dongle,观察AB灯效
A快闪结束,进入断连状态,之后切换为呼吸灯效,B快闪结束,指示灯常亮
A可以设置为自动画圈状态,同时发送B按键数据
6 补充说明¶
补充说明当前功耗测试情况,支持中遇到的问题(供参考)及已知仍可能存在的问题
6.1 功耗说明¶
LED开启的情况下,电流跟具体灯效有关,所以测试时默认关闭LED,按FN + 空格
打开/关闭LED
2.4G功耗
模式 |
全速上报(1000Hz )mA |
无按键触发60s(休眠 deepsleep) uA |
dongle未插入(休眠 standby) uA |
---|---|---|---|
2.4G |
8.25 |
36.56 |
28.37 |
蓝牙功耗
模式 |
全速上报(133Hz )mA |
一级休眠(30S关灯后)mA |
无按键10分钟(休眠 deepsleep) uA |
---|---|---|---|
BLE |
5.1 |
跟设置的latency大小有关 |
38.27 |
6.2 蓝牙启动时间说明¶
2.4G和蓝牙启动需要对controller进行初始化,controller初始化时间可以由log观测,目前测试启动时间为66ms
6.3 已知问题¶
No |
已知问题 |
目前状态 |
---|---|---|
1 |
休眠模式下切换模式过快需要复位 |
由于鼠标处于休眠状态,切换模式本应该经过断电状态,但如果切换过快,休眠状态放电不充分,芯片不能完全断电复位,仍处于休眠状态,此时唤醒可以恢复对应模式的正常运行状态 |
7 RAM/Flash资源使用情况¶
FLASH部分包含蓝牙controller固定资源120K,不包含初始位置开始的60K MCUBOOT程序,FLASH资源由于mcuboot内已支持升级功能,实际可用大小可以扩展384K
Memory region |
Used Size |
Region Size |
%age Used |
---|---|---|---|
FLASH |
119504 B |
384 KB |
30.39% |
SRAM |
43218 B |
50 KB |
84.41% |