【沁恒CH582】蓝牙协议栈的结构分析
<h3 cid="n192" mdtype="heading">蓝牙协议栈的结构</h3><p cid="n193" mdtype="paragraph">在CH583芯片中内置了一个低功耗蓝牙模块(BLE)虽然在上一节我们已经稀里糊涂使用过一次了,但是对于这个功能实现的细节没有更加深入的分析。本节,我将就芯片开源的部分和芯片中能够获取到的信息对芯片的BLE模块展开初步分析。</p>
<h4 cid="n194" mdtype="heading">BLE部分</h4>
<p cid="n195" mdtype="paragraph">虽然没有言明(也可能是我没有找到重点),可以得知在芯片中实现的物理层是BLE5.0的硬件层。使用GFSK调制和2.4GHz的频道。</p>
<p cid="n196" mdtype="paragraph">CH582M芯片的协议栈是不开源的,所以目前留给我们的突破口就仅有面向用户接口部分了。配置和应用程序的实现基于的协议是GAP和GATT。</p>
<p cid="n197" mdtype="paragraph">GAP是通用访问协议,是BLE设备内部功能对外的配置接口,主要用于设置GAP的角色,工作模式,安全特性。主要负责蓝牙设备的广播、连接和设备绑定。</p>
<figure cid="n198" mdtype="table">
<table>
<thead>
<tr cid="n199" mdtype="table_row">
<th>GAP角色</th>
<th>描述</th>
<th>对应配置文件</th>
</tr>
</thead>
<tbody>
<tr cid="n203" mdtype="table_row">
<td>广播者</td>
<td>不可以直接连接的持续广播设备</td>
<td>Broadcaster role</td>
</tr>
<tr cid="n207" mdtype="table_row">
<td>观察者</td>
<td>可以扫描广播设备但是不能发起建立连接的设备</td>
<td>Observer role</td>
</tr>
<tr cid="n211" mdtype="table_row">
<td>从机</td>
<td>可以被连接的广播设备,可以在单个链路连接中作为从机</td>
<td>Peripheral role</td>
</tr>
<tr cid="n215" mdtype="table_row">
<td>主机</td>
<td>可以扫描广播设备并发起连接,在单个链路或多个链路中作为主机</td>
<td>Central role</td>
</tr>
</tbody>
</table>
</figure>
<p cid="n219" mdtype="paragraph">接下来我们观察一下Peripheral程序中的main的实现。</p>
<p cid="n220" mdtype="paragraph">在完成基础部分的初始化之后,系统调用函数<code>CH57X_BLEInit()</code>初始化BLE外设。这一段函数的实现,给出了具体的实现。</p>
<p cid="n221" mdtype="paragraph">整个库中执行做的核心任务就是在初始化<code>bleConfig_t</code>结构体。下面给出了这个结构体的详细信息:</p>
<pre cid="n222" lang="C++" mdtype="fences" spellcheck="false">
/* BLE library config struct */
typedef struct tag_ble_config
{
uint32_t MEMAddr; // library memory start address
uint16_t MEMLen; // library memory size
uint32_t SNVAddr; // SNV flash start address,must be data-flash area or NULL(bonding information will not be saved)
uint16_t SNVBlock; // SNV flash block size ( default 512 )
uint8_t SNVNum; // SNV flash block number ( default 1 )
uint8_t BufMaxLen; // The Controller supported the maximum length of the payload,Range 27-251,ATT_MTU = BufMaxLen-4 ( default 27 )
uint8_t BufNumber; // Maximum number of sent and received packages cached by the controller( default 5 )
// Must be greater than the number of connections.
uint8_t TxNumEvent; // Maximum number of TX data in a connection event ( default 1 )
uint8_t TxPower; // Maximum transmit power level( default LL_TX_POWEER_0_DBM(0dBm) )
uint8_t WakeUpTime; // Wake up time value in one RTC count ( default 45 )
uint8_t SelRTCClock; // RTC clock select LSE,LSI(32768Hz or 32000Hz)( default:0 LSE,1: LSI(32000Hz),2:LSI(32768Hz))
// bit7: select connect timer.0:RTC timer 1:system clock timer(must disable sleep)
uint8_t RxNumEvent; // Maximum number of RX data in a connection event ( default equal to BufNumber )
uint8_t MacAddr; // MAC address,little-endian( factory default )
uint8_t ConnectNumber; // Connect number,lower two bits are peripheral number,followed by central number
uint8_t WindowWidening; // Wait rf start window
uint8_t WaitWindow; // Wait event arrive window
pfnSrandCB srandCB; // Register a program that generate a random seed
pfnSleepCB sleepCB; // Register a program that set idle mode
pfnTempSampleCB tsCB; // Register a program that read the current temperature,determine whether calibration is need
pfnLSECalibrationCB rcCB; // Register a program that RC32K clock calibration
pfnLibStatusErrorCB staCB; // Register a program that library status callback
pfnFlashReadCB readFlashCB; // Register a program that read flash
pfnFlashWriteCB writeFlashCB; // Register a program that write flash
} bleConfig_t; // Library initialization call BLE_LibInit function</pre>
<p cid="n223" mdtype="paragraph">其中最为用户需要关心的就是设备的MAC地址,在此处指定设备MAC地址之后将会将会绑定到BLE模块。并且之后调用<code>BLE_LibInit()</code>闭源函数执行蓝牙初始化。设备的固定MAC地址可以通过函数<code>GetMACAddress()</code>得到。这个MAC地址是烧录在芯片FLASH中的,可以通过FLASH直接读出。FLASH的读取函数也是闭源的,具体读出的细节并不重要。</p>
<p cid="n224" mdtype="paragraph">但是深究整个结构体,我们可以推测到BLE将会在初始化过程中校对系统时间,这个信息在实时通信过程中是非常关键的。</p>
<p cid="n225" mdtype="paragraph">接下来在<code>HAL_Init()</code>函数中注册了一个任务,并获取了其任务的ID。</p>
<pre cid="n226" lang="C++" mdtype="fences" spellcheck="false">
halTaskID = TMOS_ProcessEventRegister( HAL_ProcessEvent );</pre>
<p cid="n227" mdtype="paragraph">执行这个任务的主函数声明如下。这个函数的具体内容就是执行HAL层的各种消息响应。</p>
<pre cid="n228" lang="C++" mdtype="fences" spellcheck="false">
tmosEvents HAL_ProcessEvent( tmosTaskID task_id, tmosEvents events );</pre>
<p cid="n229" mdtype="paragraph">这一部分的内容我们下一节详细聊,我们先回到主线,观察BLE的初始化过程。</p>
<p cid="n230" mdtype="paragraph">接下来执行的任务是初始化GAP协议的相关内容,系统根据不同的角色提供了针对不同BLE所处角色的GAP初始化函数。在Peripheral例程中使用的是作为从机角色的初始化函数<code>GAPRole_PeripheralInit();</code>。这个函数的具体实现随协议栈仍然是闭源的。</p>
<p cid="n231" mdtype="paragraph">接下来到了初始化BLE的最关键部分,<code>void Peripheral_Init()</code>这个函数中给出了作为从机的BLE外设启动的全过程。接下来详细分析一下其中的步骤:</p>
<p cid="n232" mdtype="paragraph">首先使用函数<code>GAPRole_SetParameter()</code>设定GAP模块的参数,完成GAP模块的功能。其中支持的功能包括如下的这些:</p>
<pre cid="n233" lang="C++" mdtype="fences" spellcheck="false">
#define GAPROLE_PROFILEROLE 0x300 //!< Reading this parameter will return GAP Role type. Read Only. Size is uint8_t.
#define GAPROLE_IRK 0x301 //!< Identity Resolving Key. Read/Write. Size is uint8_t. Default is all 0, which means that the IRK will be randomly generated.
#define GAPROLE_SRK 0x302 //!< Signature Resolving Key. Read/Write. Size is uint8_t. Default is all 0, which means that the SRK will be randomly generated.
#define GAPROLE_SIGNCOUNTER 0x303 //!< Sign Counter. Read/Write. Size is uint32_t. Default is 0.
#define GAPROLE_BD_ADDR 0x304 //!< Device's Address. Read Only. Size is uint8_t. This item is read from the controller.
#define GAPROLE_ADVERT_ENABLED 0x305 //!< Enable/Disable Advertising. Read/Write. Size is uint8_t. Default is TRUE=Enabled.
#define GAPROLE_ADVERT_DATA 0x306 //!< Advertisement Data. Read/Write. Max size is B_MAX_ADV_EXT_LEN. Default to all 0.
#define GAPROLE_SCAN_RSP_DATA 0x307 //!< Scan Response Data. Read/Write. Max size is B_MAX_ADV_EXT_LEN. Defaults to all 0.
#define GAPROLE_ADV_EVENT_TYPE 0x308 //!< Advertisement Type. Read/Write. Size is uint8_t.Default is GAP_ADTYPE_ADV_IND.
#define GAPROLE_ADV_DIRECT_TYPE 0x309 //!< Direct Advertisement Address Type. Read/Write. Size is uint8_t. Default is ADDRTYPE_PUBLIC.
#define GAPROLE_ADV_DIRECT_ADDR 0x30A //!< Direct Advertisement Address. Read/Write. Size is uint8_t. Default is NULL.
#define GAPROLE_ADV_CHANNEL_MAP 0x30B //!< Which channels to advertise on. Read/Write Size is uint8_t. Default is GAP_ADVCHAN_ALL
#define GAPROLE_ADV_FILTER_POLICY 0x30C //!< Filter Policy. Ignored when directed advertising is used. Read/Write. Size is uint8_t. Default is GAP_FILTER_POLICY_ALL.
#define GAPROLE_STATE 0x30D //!< Reading this parameter will return GAP Peripheral Role State. Read Only. Size is uint8_t.
#define GAPROLE_MAX_SCAN_RES 0x30E //!< Maximum number of discover scan results to receive. Default is 0 = unlimited.
#define GAPROLE_MIN_CONN_INTERVAL 0x311 //!< Minimum Connection Interval to allow (n * 1.25ms).Range: 7.5 msec to 4 seconds (0x0006 to 0x0C80). Read/Write. Size is uint16_t. Default is 7.5 milliseconds (0x0006).
#define GAPROLE_MAX_CONN_INTERVAL 0x312 //!< Maximum Connection Interval to allow (n * 1.25ms).Range: 7.5 msec to 4 seconds (0x0006 to 0x0C80). Read/Write. Size is uint16_t. Default is 4 seconds (0x0C80).
// v5.x
#define GAPROLE_PHY_TX_SUPPORTED 0x313 //!< The transmitter PHYs that the Host prefers the Controller to use.Default is GAP_PHY_BIT_ALL
#define GAPROLE_PHY_RX_SUPPORTED 0x314 //!< The receiver PHYs that the Host prefers the Controller to use.Default is GAP_PHY_BIT_ALL
#define GAPROLE_PERIODIC_ADVERT_DATA 0x315 //!< Periodic advertisement Data. Read/Write. Max size is B_MAX_ADV_PERIODIC_LEN. Default to all 0.
#define GAPROLE_PERIODIC_ADVERT_ENABLED 0x316 //!< bit0:Enable/Disable Periodic Advertising. Read/Write. Size is uint8_t. Default is FALSE=Disable.</pre>
<p cid="n234" mdtype="paragraph">接下来要设置GAP GATT Server的参数,在标准库中仅仅给出了设置设备名的参数,这个设备名将会被广播以方便连接。另外支持设置的参数如下:</p>
<pre cid="n235" lang="C++" mdtype="fences" spellcheck="false">
#define GGS_DEVICE_NAME_ATT 0 // RWuint8_t
#define GGS_APPEARANCE_ATT 1 // RWuint16_t
#define GGS_PERI_PRIVACY_FLAG_ATT 2 // RWuint8_t
#define GGS_RECONNCT_ADDR_ATT 3 // RWuint8_t
#define GGS_PERI_CONN_PARAM_ATT 4 // RWsizeof(gapPeriConnectParams_t)
#define GGS_PERI_PRIVACY_FLAG_PROPS 5 // RWuint8_t
#define GGS_W_PERMIT_DEVICE_NAME_ATT 6 // W uint8_t
#define GGS_W_PERMIT_APPEARANCE_ATT 7 // W uint8_t
#define GGS_W_PERMIT_PRIVACY_FLAG_ATT 8 // W uint8_t
#define GGS_CENT_ADDR_RES_ATT 9 // RWuint8_t</pre>
<p cid="n236" mdtype="paragraph">接下来是使用函数<code>GAP_SetParamValue</code>,设定GAP的时间相关参数,具体支持设定的参数包括:</p>
<pre cid="n237" lang="C++" mdtype="fences" spellcheck="false">
// GAP_PARAMETER_ID_DEFINES GAP Parameter IDs
// Timers
#define TGAP_GEN_DISC_ADV_MIN 0 //!< Minimum time to remain advertising, when in Discoverable mode.Default 0-turns off the timeout. (n * 0.625 mSec).
#define TGAP_LIM_ADV_TIMEOUT 1 //!< Maximum time to remain advertising, when in Limited Discoverable mode.Default 180 seconds. (n * 1 seconds)
#define TGAP_DISC_SCAN 2 //!< Minimum time to perform scanning,Setting this parameter to 0 turns off the timeout.Default 10.24seconds. (n * 0.625 mSec)
// when in General Discovery process
#define TGAP_DISC_ADV_INT_MIN 3 //!< Minimum advertising interval.Default 160. (n * 0.625 mSec)
#define TGAP_DISC_ADV_INT_MAX 4 //!< Maximum advertising interval.Default 160. (n * 0.625 mSec)
#define TGAP_DISC_SCAN_INT 5 //!< Scan interval used during Link Layer Scanning state.Default 16. (n * 0.625 mSec)
#define TGAP_DISC_SCAN_WIND 6 //!< Scan window used during Link Layer Scanning state.Default 16. (n * 0.625 mSec)
// when in Connection Establishment process(1M PHY)
#define TGAP_CONN_EST_INT_MIN 7 //!< Minimum Link Layer connection interval.Default 80. (n * 1.25 mSec)
#define TGAP_CONN_EST_INT_MAX 8 //!< Maximum Link Layer connection interval.Default 80. (n * 1.25 mSec)
#define TGAP_CONN_EST_SCAN_INT 9 //!< Scan interval used during Link Layer Initiating state.Default 16. (n * 0.625 mSec)
#define TGAP_CONN_EST_SCAN_WIND 10 //!< Scan window used during Link Layer Initiating state.Default 16. (n * 0.625 mSec)
#define TGAP_CONN_EST_HIGH_SCAN_INT 11 //!< Scan interval used during Link Layer Initiating state, high duty scan cycle scan parameters (n * 0.625 mSec)
#define TGAP_CONN_EST_HIGH_SCAN_WIND 12 //!< Scan window used during Link Layer Initiating state, high duty scan cycle scan parameters (n * 0.625 mSec)
#define TGAP_CONN_EST_SUPERV_TIMEOUT 13 //!< Link Layer connection supervision timeout.Default 2000. (n * 10 mSec)
#define TGAP_CONN_EST_LATENCY 14 //!< Link Layer connection slave latency.Default 0. (in number of connection events)
#define TGAP_CONN_EST_MIN_CE_LEN 15 //!< Local informational parameter about minimum length of connection needed.Default 0. (n * 0.625 mSec)
#define TGAP_CONN_EST_MAX_CE_LEN 16 //!< Local informational parameter about maximum length of connection needed.Default 0. (n * 0.625 mSec)
// Proprietary
#define TGAP_PRIVATE_ADDR_INT 17 //!< Minimum Time Interval between private (resolvable) address changes.Default 15. (n * 1 minute)
#define TGAP_SM_TIMEOUT 18 //!< SM Message Timeout (milliseconds). Default 30 seconds.
#define TGAP_SM_MIN_KEY_LEN 19 //!< SM Minimum Key Length supported. Default 7.
#define TGAP_SM_MAX_KEY_LEN 20 //!< SM Maximum Key Length supported. Default 16.
#define TGAP_FILTER_ADV_REPORTS 21 //!< Filter duplicate advertising reports. Default TRUE.
#define TGAP_SCAN_RSP_RSSI_MIN 22 //!< Minimum RSSI required for scan responses to be reported to the app. Default -127.
#define TGAP_REJECT_CONN_PARAMS 23 //!< Whether or not to reject Connection Parameter Update Request received on Central device. Default FALSE.
#define TGAP_AUTH_TASK_ID 24 //!< Task ID override for Task Authentication control (for stack internal use only)
// v5.x
#define TGAP_ADV_TX_POWER 25 //!< Indicates the maximum power level Range: -127 ≤ N ≤ +126 Units: dBm.Default 127(Host has no preference).
#define TGAP_ADV_PRIMARY_PHY 26 //!< Indicates the PHY on which the advertising packets are transmitted on the primary advertising channel.LE 1M/LE Coded.Default GAP_PHY_VAL_LE_1M.
#define TGAP_ADV_SECONDARY_PHY 27 //!< LE 1M/LE 2M/LE Coded. Default GAP_PHY_VAL_LE_1M.
#define TGAP_ADV_SECONDARY_MAX_SKIP 28 //!< Maximum advertising events the Controller can skip before sending the AUX_ADV_IND packets on the secondary advertising channel. Default 0.
#define TGAP_ADV_ADVERTISING_SID 29 //!< Value of the Advertising SID subfield in the ADI field of the PDU Range:0-15. Default 0.
#define TGAP_ADV_SCAN_REQ_NOTIFY 30 //!< Scan request notifications enabled.Default 0-disabled.
#define TGAP_ADV_ADVERTISING_DURATION 31 //!< Advertising duration Range: 0x0001 – 0xFFFF Time = N * 10 ms. Default 0-No advertising duration.
#define TGAP_ADV_MAX_EVENTS 32 //!< indicates the maximum number of extended advertising events. Default 0.
// when in General Discovery process
#define TGAP_DISC_SCAN_PHY 33 //!< LE 1M/LE Coded. Default GAP_PHY_BIT_LE_1M.
#define TGAP_DISC_SCAN_CODED_INT 34 //!< Scan interval used during Link Layer coded Scanning state, when in General Discovery process (n * 0.625 mSec)
#define TGAP_DISC_SCAN_CODED_WIND 35 //!< Scan window used during Link Layer coded Scanning state, when in General Discovery process (n * 0.625 mSec)
#define TGAP_DISC_SCAN_DURATION 36 //!< Scan duration Range: 0x0001 – 0xFFFF Time = N * 10 ms. Default 0-Scan continuously until explicitly disable.
#define TGAP_DISC_SCAN_PERIOD 37 //!< Time interval from when the Controller started its last Scan_Duration until it begins the subsequent Scan_Duration.
//!< Default 0 Periodic scanning disabled.
// when in Connection Establishment process(2M PHY)
#define TGAP_CONN_EST_INT_PHY 38 //!< LE 1M/LE Coded. Default GAP_PHY_BIT_LE_1M.
#define TGAP_CONN_EST_2M_INT_MIN 39 //!< Minimum Link Layer connection interval.Default 80. (n * 1.25 mSec)
#define TGAP_CONN_EST_2M_INT_MAX 40 //!< Maximum Link Layer connection interval.Default 80. (n * 1.25 mSec)
#define TGAP_CONN_EST_2M_SUPERV_TIMEOUT 41 //!< Link Layer connection supervision timeout.Default 2000. (n * 10 mSec)
#define TGAP_CONN_EST_2M_LATENCY 42 //!< Link Layer connection slave latency.Default 0. (in number of connection events)
#define TGAP_CONN_EST_2M_MIN_CE_LEN 43 //!< Local informational parameter about minimum length of connection needed.Default 0. (n * 0.625 mSec)
#define TGAP_CONN_EST_2M_MAX_CE_LEN 44 //!< Local informational parameter about maximum length of connection needed.Default 0. (n * 0.625 mSec)
// when in Connection Establishment process(Coded PHY)
#define TGAP_CONN_EST_CODED_INT_MIN 45 //!< Minimum Link Layer connection interval.Default 80. (n * 1.25 mSec)
#define TGAP_CONN_EST_CODED_INT_MAX 46 //!< Maximum Link Layer connection interval.Default 80. (n * 1.25 mSec)
#define TGAP_CONN_EST_CODED_SCAN_INT 47 //!< Scan interval used during Link Layer Initiating state.Default 16. (n * 0.625 mSec)
#define TGAP_CONN_EST_CODED_SCAN_WIND 48 //!< Scan window used during Link Layer Initiating state.Default 16. (n * 0.625 mSec)
#define TGAP_CONN_EST_CODED_HIGH_SCAN_INT 49 //!< Scan interval used during Link Layer Initiating state, high duty scan cycle scan parameters (n * 0.625 mSec)
#define TGAP_CONN_EST_CODED_HIGH_SCAN_WIND 50 //!< Scan window used during Link Layer Initiating state, high duty scan cycle scan parameters (n * 0.625 mSec)
#define TGAP_CONN_EST_CODED_SUPERV_TIMEOUT 51 //!< Link Layer connection supervision timeout.Default 2000. (n * 10 mSec)
#define TGAP_CONN_EST_CODED_LATENCY 52 //!< Link Layer connection slave latency.Default 0. (in number of connection events)
#define TGAP_CONN_EST_CODED_MIN_CE_LEN 53 //!< Local informational parameter about minimum length of connection needed.Default 0. (n * 0.625 mSec)
#define TGAP_CONN_EST_CODED_MAX_CE_LEN 54 //!< Local informational parameter about maximum length of connection needed.Default 0. (n * 0.625 mSec)
// periodic advertising
#define TGAP_PERIODIC_ADV_INT_MIN 55 //!< Minimum periodic advertising interval.Range: 0x0006 to 0xFFFF.Default 160. (n * 1.25 mSec)
#define TGAP_PERIODIC_ADV_INT_MAX 56 //!< Maximum periodic advertising interval.Range: 0x0006 to 0xFFFF.Default 160. (n * 1.25 mSec)
#define TGAP_PERIODIC_ADV_PROPERTIES 57 //!< Include TxPower in the periodic advertising PDU.
#define TGAP_PARAMID_MAX 58 //!< ID MAX-valid Parameter ID</pre>
<p cid="n238" mdtype="paragraph">之后使用<code>GAPBondMgr_SetParameter</code>设置连接关系,用于描述来凝结相关的信息。</p>
<pre cid="n239" lang="C++" mdtype="fences" spellcheck="false">
// GAPBOND_PROFILE_PARAMETERS GAP Bond Manager Parameters
#define GAPBOND_PERI_PAIRING_MODE 0x400 //!< Pairing Mode: @ref GAPBOND_PAIRING_MODE_DEFINES. Read/Write. Size is uint8_t. Default is GAPBOND_PAIRING_MODE_WAIT_FOR_REQ.
#define GAPBOND_PERI_MITM_PROTECTION 0x401 //!< Man-In-The-Middle (MITM) basically turns on Passkey protection in the pairing algorithm. Read/Write. Size is uint8_t. Default is 0(disabled).
#define GAPBOND_PERI_IO_CAPABILITIES 0x402 //!< I/O capabilities.Read/Write. Size is uint8_t. Default is GAPBOND_IO_CAP_DISPLAY_ONLY @ref GAPBOND_IO_CAP_DEFINES.
#define GAPBOND_PERI_OOB_ENABLED 0x403 //!< OOB data available for pairing algorithm. Read/Write. Size is uint8_t. Default is 0(disabled).
#define GAPBOND_PERI_OOB_DATA 0x404 //!< OOB Data. Read/Write. size uint8_t. Default is all 0's.
#define GAPBOND_PERI_BONDING_ENABLED 0x405 //!< Request Bonding during the pairing process if enabled.Read/Write. Size is uint8_t. Default is 0(disabled).
#define GAPBOND_PERI_KEY_DIST_LIST 0x406 //!< The key distribution list for bonding.size is uint8_t.@ref GAPBOND_KEY_DIST_DEFINES. Default is sEncKey, sIdKey, mIdKey, mSign enabled.
#define GAPBOND_PERI_DEFAULT_PASSCODE 0x407 //!< The default passcode for MITM protection. size is uint32_t. Range is 0 - 999,999. Default is 0.
#define GAPBOND_CENT_PAIRING_MODE 0x408 //!< Pairing Mode: @refGAPBOND_PAIRING_MODE_DEFINES. Read/Write. Size is uint8_t. Default is GAPBOND_PAIRING_MODE_WAIT_FOR_REQ.
#define GAPBOND_CENT_MITM_PROTECTION 0x409 //!< Man-In-The-Middle (MITM) basically turns on Passkey protection in the pairing algorithm. Read/Write. Size is uint8_t. Default is 0(disabled).
#define GAPBOND_CENT_IO_CAPABILITIES 0x40A //!< I/O capabilities.Read/Write. Size is uint8_t. Default is GAPBOND_IO_CAP_DISPLAY_ONLY @ref GAPBOND_IO_CAP_DEFINES.
#define GAPBOND_CENT_OOB_ENABLED 0x40B //!< OOB data available for pairing algorithm. Read/Write. Size is uint8_t. Default is 0(disabled).
#define GAPBOND_CENT_OOB_DATA 0x40C //!< OOB Data. Read/Write. size uint8_t. Default is all 0's.
#define GAPBOND_CENT_BONDING_ENABLED 0x40D //!< Request Bonding during the pairing process if enabled.Read/Write. Size is uint8_t. Default is 0(disabled).
#define GAPBOND_CENT_KEY_DIST_LIST 0x40E //!< The key distribution list for bonding.size is uint8_t.@ref GAPBOND_KEY_DIST_DEFINES. Default is sEncKey, sIdKey, mIdKey, mSign enabled.
#define GAPBOND_CENT_DEFAULT_PASSCODE 0x40F //!< The default passcode for MITM protection. size is uint32_t. Range is 0 - 999,999. Default is 0.
#define GAPBOND_ERASE_ALLBONDS 0x410 //!< Erase all of the bonded devices. Write Only. No Size.
#define GAPBOND_AUTO_FAIL_PAIRING 0x411 //!< TEST MODE (DO NOT USE) to automatically send a Pairing Fail when a Pairing Request is received. Read/Write. size is uint8_t. Default is 0 (disabled).
#define GAPBOND_AUTO_FAIL_REASON 0x412 //!< TEST MODE (DO NOT USE) Pairing Fail reason when auto failing. Read/Write. size is uint8_t. Default is 0x05 (SMP_PAIRING_FAILED_NOT_SUPPORTED).
#define GAPBOND_KEYSIZE 0x413 //!< Key Size used in pairing. Read/Write. size is uint8_t. Default is 16.
#define GAPBOND_AUTO_SYNC_WL 0x414 //!< Clears the White List adds to it each unique address stored by bonds in NV. Read/Write. Size is uint8_t. Default is FALSE.
#define GAPBOND_BOND_COUNT 0x415 //!< Gets the total number of bonds stored in NV. Read Only. Size is uint8_t. Default is 0 (no bonds).
#define GAPBOND_BOND_FAIL_ACTION 0x416 //!< Possible actions Central may take upon an unsuccessful bonding. Write Only. Size is uint8_t. Default is 0x02 (Terminate link upon unsuccessful bonding).
#define GAPBOND_ERASE_SINGLEBOND 0x417 //!< Erase a single bonded device. Write only. Must provide address type followed by device address.
#define GAPBOND_BOND_AUTO 0x418 //!< Auto save bonds into FLASH. Write Only. size is uint8_t. Default is 1(enabled).
#define GAPBOND_BOND_UPDATE 0x419 //!< Save current bonds into FLASH. Write Only. No Size.
#define GAPBOND_DISABLE_SINGLEBOND 0x41A //!< Disable a single bonded device. Write only. Must provide address type followed by device address.
#define GAPBOND_ENABLE_SINGLEBOND 0x41B //!< Ensable a single bonded device. Write only. Must provide address type followed by device address.
#define GAPBOND_DISABLE_ALLBONDS 0x41C //!< Disable all of the bonded devices. Write Only. No Size.
#define GAPBOND_ENABLE_ALLBONDS 0x41D //!< Ensable all of the bonded devices. Write Only. No Size.
#define GAPBOND_ERASE_AUTO 0x41E //!< Auto erase all of the bonded devices when the maximum number is reached.Size is uint8_t. Default is 1(enabled).
#define GAPBOND_AUTO_SYNC_RL 0x41F //!< Clears the Resolving List adds to it each unique address stored by bonds in NV. Read/Write. Size is uint8_t. Default is FALSE.</pre>
<p cid="n240" mdtype="paragraph">接下来的代码就是注册一个GATT的服务,并注册相关回调响应函数。</p>
<p cid="n241" mdtype="paragraph">最终进入主循环,将系统的权限交由TMOS操作系统。</p>
<p cid="n242" mdtype="paragraph">我们可以在回调函数中找到响应的处理代码段,比如在BLE_UART例程中的函数:</p>
<pre cid="n243" lang="C++" mdtype="fences" spellcheck="false">
static bStatus_t ble_uart_ReadAttrCB(
uint16 connHandle,
gattAttribute_t *pAttr,
uint8 *pValue, uint16 *pLen,
uint16 offset,
uint16 maxLen,
uint8 method );</pre>
<p cid="n244" mdtype="paragraph">这个函数将有实时嵌入式系统进行调用,最终支持整个逻辑层功能的实现。</p>
<h4 cid="n245" mdtype="heading">操作系统层TMOS</h4>
<p cid="n246" mdtype="paragraph">在这套程序中提供了一个基础但是强大的操作系统。其基本的使用框架就是注册响应函数,发布消息,响应消息。TMOS的执行方式就是在主循环中按照特定的优先级执行相关的响应例程。从数据手册中描述上应该是通过队列的方式实现,是不是有可能用极左树(笑)。</p>
<p cid="n247" mdtype="paragraph">接下来罗列一下最关键的几项函数:</p>
<pre cid="n248" lang="C++" mdtype="fences" spellcheck="false">
// 创建一个任务:
extern tmosTaskID TMOS_ProcessEventRegister( pTaskEventHandlerFn eventCb );
// 回调函数原型;
typedef tmosEvents (*pTaskEventHandlerFn)( tmosTaskID taskID, tmosEvents event );
tmosEvents EventController( tmosTaskID task_id, tmosEvents events);
// 发送一个消息(执行一个时事件)
extern bStatus_t tmos_start_task( tmosTaskID taskID, tmosEvents event, tmosTimer time );</pre>
<p cid="n249" mdtype="paragraph">在回调函数中可以按照下面的模板进行任务的响应:</p>
<pre cid="n250" lang="C++" mdtype="fences" spellcheck="false">
tmosEvents HAL_ProcessEvent( tmosTaskID task_id, tmosEvents events )
{
// 初始化局部变量
uint8 * msgPtr;
// 从HAL层扒一点示例过来,有一个直观感受
// 处理HAL层消息,调用tmos_msg_receive读取消息,处理完成后删除消息。
if ( events & SYS_EVENT_MSG )
{
// 样例
msgPtr = tmos_msg_receive( task_id );
if ( msgPtr )
{
/* De-allocate */
tmos_msg_deallocate( msgPtr );
}
return events ^ SYS_EVENT_MSG;
}
// 这里是消息响应的框架
if ( events & TASK1 )
{}
if(events & TASK2)
{}
return 0;
} </pre>
<p cid="n251" mdtype="paragraph">除此之外,系统也提供了堆管理的功能提供了堆的申请、释放和内存基础操作。</p>
<pre cid="n252" lang="C++" mdtype="fences" spellcheck="false">
extern uint32_t tmos_rand( void ); // pseudo-random number
extern BOOL tmos_memcmp( const void *src1, const void *src2, uint32_t len ); // TRUE - same, FALSE - different
extern BOOL tmos_isbufset( uint8_t *buf, uint8_t val, uint32_t len ); // TRUE if all "val",FALSE otherwise
extern uint32_t tmos_strlen( char *pString );
extern void tmos_memset( void * pDst, uint8_t Value, uint32_t len );
extern void tmos_memcpy( void *dst, const void *src, uint32_t len ); // Generic memory copy.</pre>
<p cid="n253" mdtype="paragraph">由于这样的任务并非抢占式,因此,我们在书写每一个event时应当尽量保证其中的内容尽可能精练。</p>
分析这个确实需要耐心跟时间,我也就用什么看什么,但是这个任务系统要处理复杂的程序还是不是很合适。 <p>代码你用编辑器的代码插入功能会清晰些</p>
nmg 发表于 2022-4-27 17:37
代码你用编辑器的代码插入功能会清晰些
<p>是这样的,我是markdown直接编辑好贴过来的,其实还好</p>
<p>很不错<img height="48" src="https://bbs.eeworld.com.cn/static/editor/plugins/hkemoji/sticker/facebook/wanwan88.gif" width="59" /></p>
<p>感觉挺nb的,要是能硬件pin对pin,软件完全兼容一些现有的方案就太棒了!</p>
<p>感谢分享 用ch571f做过一个mesh灯具</p>
<p> </p>
页:
[1]