BLE_DCF_TYQ_CH592F/APP/peripheral.c

1010 lines
34 KiB
C
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/********************************** (C) COPYRIGHT *******************************
* File Name : peripheral.C
* Author : WCH
* Version : V1.0
* Date : 2018/12/10
* Description : 外设从机多连接应用程序,初始化广播连接参数,然后广播,连接主机后,
* 请求更新连接参数,通过自定义服务传输数据
*********************************************************************************
* Copyright (c) 2021 Nanjing Qinheng Microelectronics Co., Ltd.
* Attention: This software (modified or not) and binary are used for
* microcontroller manufactured by Nanjing Qinheng Microelectronics.
*******************************************************************************/
/*********************************************************************
* INCLUDES
*/
#include "CONFIG.h"
#include "devinfoservice.h"
#include "gattprofile.h"
#include "peripheral.h"
#include "bsp_valve.h"
#include "bsp_uart.h"
#include "log.h"
// #include "bsp_i2c.h"
#include "bsp_gxhtc3c.h"
#include "bsp_adc.h"
#include "bsp_beep_led_emv.h"
#include "SLEEP.h"
#undef LOG_ENABLE
#define LOG_ENABLE 1
#undef LOG_TAG
#define LOG_TAG "peripheral"
volatile uint8_t mtu_flag = 0;
static volatile bool periodic_upload_block_flag = false;
void BSP_NeeedReplyCMdFirst(void)
{
periodic_upload_block_flag = true;
}
void BSP_NoNeeedReplyCMd(void)
{
periodic_upload_block_flag = false;
}
// How often to perform periodic event
// TODO:这里长点功耗低
#define SBP_PERIODIC_EVT_PERIOD (1600 * 60 * 3) // (160 = 100ms)
// How often to perform read rssi event
#define SBP_READ_RSSI_EVT_PERIOD (1600 * 3) // (160 = 100ms)
// Parameter update delay
#define SBP_PARAM_UPDATE_DELAY (1600 * 1)
// PHY update delay
#define SBP_PHY_UPDATE_DELAY (1600 * 2)
// What is the advertising interval when device is discoverable (units of 625us, 80=50ms)
#define DEFAULT_ADVERTISING_INTERVAL (160 * 8)
// Limited discoverable mode advertises for 30.72s, and then stops
// General discoverable mode advertises indefinitely
#define DEFAULT_DISCOVERABLE_MODE GAP_ADTYPE_FLAGS_GENERAL
// Minimum connection interval (units of 1.25ms, 6=7.5ms)
#define DEFAULT_DESIRED_MIN_CONN_INTERVAL (80 * 4) // (80 = 100ms)
// Maximum connection interval (units of 1.25ms, 100=125ms)
#define DEFAULT_DESIRED_MAX_CONN_INTERVAL (80 * 6)
// Slave latency to use parameter update
#define DEFAULT_DESIRED_SLAVE_LATENCY 0
// Supervision timeout value (units of 10ms, 100=1s)
#define DEFAULT_DESIRED_CONN_TIMEOUT (100 * 3)
// Company Identifier: WCH
#define WCH_COMPANY_ID 0x07D7
#define MAC_NAME "TYQ-93:B4:8F:10:53:5C"
// TYQ-93:B4:8F:10:53:5C
#define MAC_NAME_LEN 22
uint8_t Peripheral_TaskID = INVALID_TASK_ID; // Task ID for internal task/event processing
// 蓝牙广播包的最大长度是37个字节其中设备地址占用了6个字节只有31个字节是可用的。
// TODO:响应体名称加上MAC地址
// GAP - SCAN RSP data (max size = 31 bytes)
static uint8_t scanRspData[] = {
// complete name
0x12, // length of this data
GAP_ADTYPE_LOCAL_NAME_COMPLETE,
'B',
'L',
'E',
'T',
'Y',
'Q',
' ',
'P',
'e',
'r',
'i',
'p',
'h',
'e',
'r',
'a',
'l',
// connection interval range
0x05, // length of this data
GAP_ADTYPE_SLAVE_CONN_INTERVAL_RANGE,
LO_UINT16(DEFAULT_DESIRED_MIN_CONN_INTERVAL), // 100ms
HI_UINT16(DEFAULT_DESIRED_MIN_CONN_INTERVAL),
LO_UINT16(DEFAULT_DESIRED_MAX_CONN_INTERVAL), // 1s
HI_UINT16(DEFAULT_DESIRED_MAX_CONN_INTERVAL),
// Tx power level
0x02, // length of this data
GAP_ADTYPE_POWER_LEVEL,
0 // 0dBm
};
// GAP - Advertisement data (max size = 31 bytes, though this is
// best kept short to conserve power while advertising)
static uint8_t advertData[] = {
// Flags; this sets the device to use limited discoverable
// mode (advertises for 30 seconds at a time) instead of general
// discoverable mode (advertises indefinitely)
0x02, // length of this data
GAP_ADTYPE_FLAGS,
DEFAULT_DISCOVERABLE_MODE | GAP_ADTYPE_FLAGS_BREDR_NOT_SUPPORTED,
// service UUID, to notify central devices what services are included
// in this peripheral
0x03, // length of this data
GAP_ADTYPE_16BIT_MORE, // some of the UUID's, but not all
LO_UINT16(SIMPLEPROFILE_SERV_UUID),
HI_UINT16(SIMPLEPROFILE_SERV_UUID)};
// GAP GATT Attributes
static uint8_t attDeviceName[GAP_DEVICE_NAME_LEN] = "BLE_TYQ";
// Connection item list
static peripheralConnItem_t peripheralConnList;
static uint16_t peripheralMTU = ATT_MTU_SIZE;
/*********************************************************************
* LOCAL FUNCTIONS
*/
static void Peripheral_ProcessTMOSMsg(tmos_event_hdr_t *pMsg);
static void peripheralStateNotificationCB(gapRole_States_t newState, gapRoleEvent_t *pEvent);
static void performPeriodicTask(void);
static void simpleProfileChangeCB(uint8_t paramID, uint8_t *pValue, uint16_t len);
static void peripheralParamUpdateCB(uint16_t connHandle, uint16_t connInterval,
uint16_t connSlaveLatency, uint16_t connTimeout);
static void peripheralInitConnItem(peripheralConnItem_t *peripheralConnList);
static void peripheralRssiCB(uint16_t connHandle, int8_t rssi);
static void peripheralChar4Notify(uint8_t *pValue, uint16_t len);
/*********************************************************************
* PROFILE CALLBACKS
*/
// GAP Role Callbacks
static gapRolesCBs_t Peripheral_PeripheralCBs = {
peripheralStateNotificationCB, // Profile State Change Callbacks
peripheralRssiCB, // When a valid RSSI is read from controller (not used by application)
peripheralParamUpdateCB};
// Broadcast Callbacks
static gapRolesBroadcasterCBs_t Broadcaster_BroadcasterCBs = {
NULL, // Not used in peripheral role
NULL // Receive scan request callback
};
// GAP Bond Manager Callbacks
static gapBondCBs_t Peripheral_BondMgrCBs = {
NULL, // Passcode callback (not used by application)
NULL, // Pairing / Bonding state Callback (not used by application)
NULL // oob callback
};
// Simple GATT Profile Callbacks
static simpleProfileCBs_t Peripheral_SimpleProfileCBs = {
simpleProfileChangeCB // Characteristic value change callback
};
/*********************************************************************
* PUBLIC FUNCTIONS
*/
/*********************************************************************
* @fn Peripheral_Init
*
* @brief Initialization function for the Peripheral App Task.
* This is called during initialization and should contain
* any application specific initialization (ie. hardware
* initialization/setup, table initialization, power up
* notificaiton ... ).
*
* @param task_id - the ID assigned by TMOS. This ID should be
* used to send messages and set timers.
*
* @return none
*/
void Peripheral_Init()
{
Peripheral_TaskID = TMOS_ProcessEventRegister(Peripheral_ProcessEvent);
// Setup the GAP Peripheral Role Profile
{
// 开启广播使能
uint8_t initial_advertising_enable = TRUE;
// 最小连接间隔
uint16_t desired_min_interval = DEFAULT_DESIRED_MIN_CONN_INTERVAL;
// 最大连接间隔
uint16_t desired_max_interval = DEFAULT_DESIRED_MAX_CONN_INTERVAL;
// Set the GAP Role Parameters
GAPRole_SetParameter(GAPROLE_ADVERT_ENABLED, sizeof(uint8_t), &initial_advertising_enable);
GAPRole_SetParameter(GAPROLE_SCAN_RSP_DATA, sizeof(scanRspData), scanRspData);
GAPRole_SetParameter(GAPROLE_ADVERT_DATA, sizeof(advertData), advertData);
GAPRole_SetParameter(GAPROLE_MIN_CONN_INTERVAL, sizeof(uint16_t), &desired_min_interval);
GAPRole_SetParameter(GAPROLE_MAX_CONN_INTERVAL, sizeof(uint16_t), &desired_max_interval);
}
{
uint16_t advInt = DEFAULT_ADVERTISING_INTERVAL;
// Set advertising interval
GAP_SetParamValue(TGAP_DISC_ADV_INT_MIN, advInt);
GAP_SetParamValue(TGAP_DISC_ADV_INT_MAX, advInt);
// https://www.cnblogs.com/debugdabiaoge/p/17871551.html
// 默认从机在回复扫描请求后,会结束广播事件(默认广播应该是 37 38 39 在 3 个信道轮发)
// 如下使能后,可以保证广播包不受扫描请求的影响
// uint16_t adv_event_contnue=1<<1;
// GAP_SetParamValue(TGAP_ADV_SCAN_REQ_NOTIFY, adv_event_contnue);
// Enable scan req notify
GAP_SetParamValue(TGAP_ADV_SCAN_REQ_NOTIFY, ENABLE);
}
// Setup the GAP Bond Manager
{
uint32_t passkey = 0; // passkey "000000"
uint8_t pairMode = GAPBOND_PAIRING_MODE_WAIT_FOR_REQ;
uint8_t mitm = TRUE;
uint8_t bonding = TRUE;
uint8_t ioCap = GAPBOND_IO_CAP_DISPLAY_ONLY;
GAPBondMgr_SetParameter(GAPBOND_PERI_DEFAULT_PASSCODE, sizeof(uint32_t), &passkey);
GAPBondMgr_SetParameter(GAPBOND_PERI_PAIRING_MODE, sizeof(uint8_t), &pairMode);
GAPBondMgr_SetParameter(GAPBOND_PERI_MITM_PROTECTION, sizeof(uint8_t), &mitm);
GAPBondMgr_SetParameter(GAPBOND_PERI_IO_CAPABILITIES, sizeof(uint8_t), &ioCap);
GAPBondMgr_SetParameter(GAPBOND_PERI_BONDING_ENABLED, sizeof(uint8_t), &bonding);
}
// Initialize GATT attributes
GGS_AddService(GATT_ALL_SERVICES); // GAP
GATTServApp_AddService(GATT_ALL_SERVICES); // GATT attributes
DevInfo_AddService(); // Device Information Service
SimpleProfile_AddService(GATT_ALL_SERVICES); // Simple GATT Profile
// Set the GAP Characteristics
GGS_SetParameter(GGS_DEVICE_NAME_ATT, GAP_DEVICE_NAME_LEN, attDeviceName);
// Setup the SimpleProfile Characteristic Values
{
uint8_t charValue1[SIMPLEPROFILE_CHAR1_LEN] = {0};
uint8_t charValue2[SIMPLEPROFILE_CHAR2_LEN] = {0};
uint8_t charValue3[SIMPLEPROFILE_CHAR3_LEN] = {0};
uint8_t charValue4[SIMPLEPROFILE_CHAR4_LEN] = {0};
uint8_t charValue5[SIMPLEPROFILE_CHAR5_LEN] = {0, 0, 0, 0, 0};
SimpleProfile_SetParameter(SIMPLEPROFILE_CHAR1, SIMPLEPROFILE_CHAR1_LEN, charValue1);
SimpleProfile_SetParameter(SIMPLEPROFILE_CHAR2, SIMPLEPROFILE_CHAR2_LEN, charValue2);
SimpleProfile_SetParameter(SIMPLEPROFILE_CHAR3, SIMPLEPROFILE_CHAR3_LEN, charValue3);
SimpleProfile_SetParameter(SIMPLEPROFILE_CHAR4, SIMPLEPROFILE_CHAR4_LEN, charValue4);
SimpleProfile_SetParameter(SIMPLEPROFILE_CHAR5, SIMPLEPROFILE_CHAR5_LEN, charValue5);
}
// Init Connection Item
peripheralInitConnItem(&peripheralConnList);
// Register callback with SimpleGATTprofile
SimpleProfile_RegisterAppCBs(&Peripheral_SimpleProfileCBs);
// Register receive scan request callback
GAPRole_BroadcasterSetCB(&Broadcaster_BroadcasterCBs);
// Setup a delayed profile startup
tmos_set_event(Peripheral_TaskID, SBP_START_DEVICE_EVT);
// https://www.cnblogs.com/ZYL-FS/p/18061479
GATT_InitClient();
}
/*********************************************************************
* @fn peripheralInitConnItem
*
* @brief Init Connection Item
*
* @param peripheralConnList -
*
* @return NULL
*/
static void peripheralInitConnItem(peripheralConnItem_t *peripheralConnList)
{
peripheralConnList->connHandle = GAP_CONNHANDLE_INIT;
peripheralConnList->connInterval = 0;
peripheralConnList->connSlaveLatency = 0;
peripheralConnList->connTimeout = 0;
}
/*********************************************************************
* @fn Peripheral_ProcessEvent
*
* @brief Peripheral Application Task event processor. This function
* is called to process all events for the task. Events
* include timers, messages and any other user defined events.
*
* @param task_id - The TMOS assigned task ID.
* @param events - events to process. This is a bit map and can
* contain more than one event.
*
* @return events not processed
*/
uint16_t Peripheral_ProcessEvent(uint8_t task_id, uint16_t events)
{
// VOID task_id; // TMOS required parameter that isn't used in this function
if (events & SYS_EVENT_MSG)
{
uint8_t *pMsg;
if ((pMsg = tmos_msg_receive(Peripheral_TaskID)) != NULL)
{
Peripheral_ProcessTMOSMsg((tmos_event_hdr_t *)pMsg);
// Release the TMOS message
tmos_msg_deallocate(pMsg);
}
// return unprocessed events
return (events ^ SYS_EVENT_MSG);
}
if (events & SBP_START_DEVICE_EVT)
{
// Start the Device
GAPRole_PeripheralStartDevice(Peripheral_TaskID, &Peripheral_BondMgrCBs, &Peripheral_PeripheralCBs);
return (events ^ SBP_START_DEVICE_EVT);
}
if (events & SBP_REPLY_CMD_EVT)
{
logDebug("SBP_REPLY_CMD_EVT");
peripheralChar4Notify((uint8_t *)&RelyData.buf[0], RelyData.len);
BSP_NoNeeedReplyCMd();
tmos_set_event(led_task_id, LED_SHOW_START_EVT);
return (events ^ SBP_REPLY_CMD_EVT);
}
if (events & SBP_PERIODIC_EVT)
{
// 防止主机下发指令,从机回复响应的时候,先传的是状态数据
if (periodic_upload_block_flag == false && mtu_flag == 1)
{
// Perform periodic application task
performPeriodicTask();
// Restart timer
tmos_start_task(Peripheral_TaskID, SBP_PERIODIC_EVT, SBP_PERIODIC_EVT_PERIOD);
}
else
{
// 需要等先回复了下发的指令1s 之后再尝试回复状态数据
tmos_start_task(Peripheral_TaskID, SBP_PERIODIC_EVT, MS1_TO_SYSTEM_TIME(1000));
}
return (events ^ SBP_PERIODIC_EVT);
}
if (events & SBP_PARAM_UPDATE_EVT)
{
// Send connect param update request
GAPRole_PeripheralConnParamUpdateReq(peripheralConnList.connHandle,
DEFAULT_DESIRED_MIN_CONN_INTERVAL,
DEFAULT_DESIRED_MAX_CONN_INTERVAL,
DEFAULT_DESIRED_SLAVE_LATENCY,
DEFAULT_DESIRED_CONN_TIMEOUT,
Peripheral_TaskID);
return (events ^ SBP_PARAM_UPDATE_EVT);
}
if (events & SBP_PHY_UPDATE_EVT)
{
// start phy update
logDebug("PHY Update %x...", GAPRole_UpdatePHY(peripheralConnList.connHandle, 0,
GAP_PHY_BIT_LE_2M, GAP_PHY_BIT_LE_2M, 0));
return (events ^ SBP_PHY_UPDATE_EVT);
}
if (events & SBP_READ_RSSI_EVT)
{
GAPRole_ReadRssiCmd(peripheralConnList.connHandle);
tmos_start_task(Peripheral_TaskID, SBP_READ_RSSI_EVT, SBP_READ_RSSI_EVT_PERIOD);
return (events ^ SBP_READ_RSSI_EVT);
}
// Discard unknown events
return 0;
}
/*********************************************************************
* @fn Peripheral_ProcessGAPMsg
*
* @brief Process an incoming task message.
*
* @param pMsg - message to process
*
* @return none
*/
static void Peripheral_ProcessGAPMsg(gapRoleEvent_t *pEvent)
{
switch (pEvent->gap.opcode)
{
case GAP_SCAN_REQUEST_EVENT:
{
logDebug("Receive scan req from %x %x %x %x %x %x ..", pEvent->scanReqEvt.scannerAddr[0],
pEvent->scanReqEvt.scannerAddr[1], pEvent->scanReqEvt.scannerAddr[2], pEvent->scanReqEvt.scannerAddr[3],
pEvent->scanReqEvt.scannerAddr[4], pEvent->scanReqEvt.scannerAddr[5]);
break;
}
case GAP_PHY_UPDATE_EVENT:
{
logDebug("Phy update Rx:%x Tx:%x ..", pEvent->linkPhyUpdate.connRxPHYS, pEvent->linkPhyUpdate.connTxPHYS);
break;
}
default:
break;
}
}
/*********************************************************************
* @fn Peripheral_ProcessTMOSMsg
*
* @brief Process an incoming task message.
*
* @param pMsg - message to process
*
* @return none
*/
static void Peripheral_ProcessTMOSMsg(tmos_event_hdr_t *pMsg)
{
switch (pMsg->event)
{
case GAP_MSG_EVENT:
{
Peripheral_ProcessGAPMsg((gapRoleEvent_t *)pMsg);
break;
}
case GATT_MSG_EVENT:
{
gattMsgEvent_t *pMsgEvent;
pMsgEvent = (gattMsgEvent_t *)pMsg;
if (pMsgEvent->method == ATT_MTU_UPDATED_EVENT)
{
peripheralMTU = pMsgEvent->msg.exchangeMTUReq.clientRxMTU;
mtu_flag = 1;
logDebug("****mtu exchange: %d****", pMsgEvent->msg.exchangeMTUReq.clientRxMTU);
// TODO连上之后先给个状态回应
// tmos_set_event(vavle_task_id, VAVLE_UPDATE_EVT);
performPeriodicTask();
// gValveData.bat = BSP_ReadVbat();
tmos_start_task(Peripheral_TaskID, SBP_PERIODIC_EVT, MS1_TO_SYSTEM_TIME(5000));
tmos_set_event(led_task_id, CONNECT_BEEP_START_EVT);
}
break;
}
default:
break;
}
}
/*********************************************************************
* @fn Peripheral_LinkEstablished
*
* @brief Process link established.
*
* @param pEvent - event to process
*
* @return none
*/
static void Peripheral_LinkEstablished(gapRoleEvent_t *pEvent)
{
gapEstLinkReqEvent_t *event = (gapEstLinkReqEvent_t *)pEvent;
// See if already connected
if (peripheralConnList.connHandle != GAP_CONNHANDLE_INIT)
{
GAPRole_TerminateLink(pEvent->linkCmpl.connectionHandle);
logDebug("Connection max...");
}
else
{
peripheralConnList.connHandle = event->connectionHandle;
peripheralConnList.connInterval = event->connInterval;
peripheralConnList.connSlaveLatency = event->connLatency;
peripheralConnList.connTimeout = event->connTimeout;
peripheralMTU = ATT_MTU_SIZE;
// peripheralMTU = BLE_BUFF_MAX_LEN - 4;
// Set timer for periodic event
tmos_start_task(Peripheral_TaskID, SBP_PERIODIC_EVT, SBP_PERIODIC_EVT_PERIOD);
// Set timer for param update event
tmos_start_task(Peripheral_TaskID, SBP_PARAM_UPDATE_EVT, SBP_PARAM_UPDATE_DELAY);
// Start read rssi
tmos_start_task(Peripheral_TaskID, SBP_READ_RSSI_EVT, SBP_READ_RSSI_EVT_PERIOD);
// https://www.cnblogs.com/ZYL-FS/p/17759138.html
// 使能通知
enable_notify(peripheralConnList.connHandle, ENABLE);
logDebug("Conn %x - Int %x= %.1fms", event->connectionHandle, event->connInterval, event->connInterval * 1.25);
}
}
/*********************************************************************
* @fn Peripheral_LinkTerminated
*
* @brief Process link terminated.
*
* @param pEvent - event to process
*
* @return none
*/
static void Peripheral_LinkTerminated(gapRoleEvent_t *pEvent)
{
gapTerminateLinkEvent_t *event = (gapTerminateLinkEvent_t *)pEvent;
if (event->connectionHandle == peripheralConnList.connHandle)
{
peripheralConnList.connHandle = GAP_CONNHANDLE_INIT;
peripheralConnList.connInterval = 0;
peripheralConnList.connSlaveLatency = 0;
peripheralConnList.connTimeout = 0;
tmos_stop_task(Peripheral_TaskID, SBP_PERIODIC_EVT);
tmos_stop_task(Peripheral_TaskID, SBP_READ_RSSI_EVT);
// Restart advertising
{
// 三个广播通道全部打开
// uint8_t init_adv_channel_map = GAP_ADVCHAN_ALL ;
// GAPRole_SetParameter( GAPROLE_ADV_CHANNEL_MAP, sizeof( uint8_t ), &init_adv_channel_map);
mtu_flag = 0;
uint8_t advertising_enable = TRUE;
GAPRole_SetParameter(GAPROLE_ADVERT_ENABLED, sizeof(uint8_t), &advertising_enable);
}
}
else
{
logError("ERR..");
}
}
/*********************************************************************
* @fn peripheralRssiCB
*
* @brief RSSI callback.
*
* @param connHandle - connection handle
* @param rssi - RSSI
*
* @return none
*/
static void peripheralRssiCB(uint16_t connHandle, int8_t rssi)
{
gValveData.rssi = rssi;
logDebug("RSSI %d dB Conn %x ", gValveData.rssi, connHandle);
}
/*********************************************************************
* @fn peripheralParamUpdateCB
*
* @brief Parameter update complete callback
*
* @param connHandle - connect handle
* connInterval - connect interval
* connSlaveLatency - connect slave latency
* connTimeout - connect timeout
*
* @return none
*/
static void peripheralParamUpdateCB(uint16_t connHandle, uint16_t connInterval,
uint16_t connSlaveLatency, uint16_t connTimeout)
{
if (connHandle == peripheralConnList.connHandle)
{
peripheralConnList.connInterval = connInterval;
peripheralConnList.connSlaveLatency = connSlaveLatency;
peripheralConnList.connTimeout = connTimeout;
logDebug("ParamUpdateCB (Handle)%x - (connInt 0x%x=%.1fms) - (connSlaveLatency) %x - (connTimeout 0x%x=%dms) ", connHandle, connInterval, connInterval * 1.25, connSlaveLatency, connTimeout * 10, connTimeout * 10);
}
else
{
logError("ERR..");
}
}
/*********************************************************************
* @fn peripheralStateNotificationCB
*
* @brief Notification from the profile of a state change.
*
* @param newState - new state
*
* @return none
*/
static void peripheralStateNotificationCB(gapRole_States_t newState, gapRoleEvent_t *pEvent)
{
switch (newState & GAPROLE_STATE_ADV_MASK)
{
case GAPROLE_STARTED:
logDebug("Initialized..");
break;
case GAPROLE_ADVERTISING:
if (pEvent->gap.opcode == GAP_LINK_TERMINATED_EVENT)
{
Peripheral_LinkTerminated(pEvent);
logDebug("Disconnected.. Reason:%x", pEvent->linkTerminate.reason);
logDebug("Advertising..");
}
else if (pEvent->gap.opcode == GAP_MAKE_DISCOVERABLE_DONE_EVENT)
{
logDebug("Advertising..");
}
break;
case GAPROLE_CONNECTED:
if (pEvent->gap.opcode == GAP_LINK_ESTABLISHED_EVENT)
{
Peripheral_LinkEstablished(pEvent);
logDebug("Connected..");
// 在蓝牙建立连接之后,调用 GATT ExchangeMTU 来修改 MTU 的值
// Update MTU
attExchangeMTUReq_t req = {
.clientRxMTU = BLE_BUFF_MAX_LEN - 4,
};
GATT_ExchangeMTU(peripheralConnList.connHandle, &req, Peripheral_TaskID);
// Peripheral_SetMacName();
}
break;
case GAPROLE_CONNECTED_ADV:
if (pEvent->gap.opcode == GAP_MAKE_DISCOVERABLE_DONE_EVENT)
{
logDebug("Connected Advertising..");
}
break;
case GAPROLE_WAITING:
if (pEvent->gap.opcode == GAP_END_DISCOVERABLE_DONE_EVENT)
{
logDebug("Waiting for advertising..");
}
else if (pEvent->gap.opcode == GAP_LINK_TERMINATED_EVENT)
{
Peripheral_LinkTerminated(pEvent);
logDebug("Disconnected.. Reason:%x", pEvent->linkTerminate.reason);
}
else if (pEvent->gap.opcode == GAP_LINK_ESTABLISHED_EVENT)
{
if (pEvent->gap.hdr.status != SUCCESS)
{
logDebug("Waiting for advertising..");
}
else
{
logError("Err..");
}
}
else
{
logError("Err..%x", pEvent->gap.opcode);
}
break;
case GAPROLE_ERROR:
logError("Err..");
break;
default:
break;
}
}
/*********************************************************************
* @fn performPeriodicTask
*
* @brief Perform a periodic application task. This function gets
* called every five seconds as a result of the SBP_PERIODIC_EVT
* TMOS event. In this example, the value of the third
* characteristic in the SimpleGATTProfile service is retrieved
* from the profile, and then copied into the value of the
* the fourth characteristic.
*
* @param none
*
* @return none
*/
static void performPeriodicTask(void)
{
// if (boost_en_flag == 0 && GPIOA_ReadITFlagBit(BOOST_APIN) == 0)
if (boost_en_flag == 0)
{
gValveData.bat = BSP_ReadVbat();
// TODO温湿度传感器读错的话就不发了
float _humi, _temp;
if (BSP_ReadTempHumi(&_humi, &_temp) == 0)
{
gValveData.temp = (int8_t)_temp;
gValveData.humi = (uint8_t)_humi;
if (gValveData.temp >= HIGN_TEMP_CLOSE_C)
{
logDebug("高温关阀");
tmos_set_event(vavle_task_id, VAVLE_CLOSE_START_EVT);
// 给个回应
tmos_start_task(Peripheral_TaskID, SBP_PERIODIC_EVT, MS1_TO_SYSTEM_TIME(6000));
}
}
else
{
gValveData.temp = -100;
gValveData.humi = 100;
logError("Read TempHumi Err");
// return;
}
#if 1
logDebug("switch_status:%d Temp:%d Bat:%d Humi:%d%% RSSI: %d"
, gValveData.switch_status, gValveData.temp, gValveData.bat, gValveData.humi, gValveData.rssi);
#endif
TsRawFrameData RawData;
BSP_VALVE_Generate_UploadData(&RawData);
peripheralChar4Notify(&RawData.buf[0], RawData.len);
tmos_set_event(led_task_id, LED_SHOW_START_EVT);
}
// else if(GPIOA_ReadITFlagBit(BOOST_APIN) == 1)
else
{
tmos_start_task(Peripheral_TaskID, SBP_PERIODIC_EVT, MS1_TO_SYSTEM_TIME(1000));
}
}
/*********************************************************************
* @fn peripheralChar4Notify
*
* @brief Prepare and send simpleProfileChar4 notification
*
* @param pValue - data to notify
* len - length of data
*
* @return none
*/
static void peripheralChar4Notify(uint8_t *pValue, uint16_t len)
{
#if 1
attHandleValueNoti_t noti;
if (len > (peripheralMTU - 3))
{
logDebug("Too large noti");
return;
}
noti.len = len;
noti.pValue = GATT_bm_alloc(peripheralConnList.connHandle, ATT_HANDLE_VALUE_NOTI, noti.len, NULL, 0);
if (noti.pValue)
{
tmos_memcpy(noti.pValue, pValue, noti.len);
if (simpleProfile_Notify(peripheralConnList.connHandle, &noti) != SUCCESS)
{
logError("Noti Err");
GATT_bm_free((gattMsg_t *)&noti, ATT_HANDLE_VALUE_NOTI);
}
else
{
logDebug("Noti Success");
}
}
#endif
}
/*********************************************************************
* @fn simpleProfileChangeCB
*
* @brief Callback from SimpleBLEProfile indicating a value change
*
* @param paramID - parameter ID of the value that was changed.
* pValue - pointer to data that was changed
* len - length of data
*
* @return none
*/
static void simpleProfileChangeCB(uint8_t paramID, uint8_t *pValue, uint16_t len)
{
// tmos_event_hdr_t *test_message;
// TsRawFrameData RawData;
BSP_NeeedReplyCMdFirst();
switch (paramID)
{
case SIMPLEPROFILE_CHAR1:
{
uint8_t newValue[SIMPLEPROFILE_CHAR1_LEN];
tmos_memcpy(newValue, pValue, len);
logDebug("profile ChangeCB CHAR1.. Start");
for (uint8_t i = 0; i < len; i++)
{
logDebug("%02x ", newValue[i]);
// BSP_UART1_TxLoop();
}
logDebug("\n profile ChangeCB CHAR1.. End");
// test_message =(tmos_event_hdr_t*) tmos_msg_allocate(sizeof(tmos_event_hdr_t));
// BSP_UART1_TxLoop();
break;
}
case SIMPLEPROFILE_CHAR3:
{
// uint8_t newValue[SIMPLEPROFILE_CHAR3_LEN];
// tmos_memset(newValue, 0, sizeof(newValue));
// tmos_memcpy(newValue, pValue, len);
logDebug("CHAR3 Start");
// logHexDumpAll(newValue, len);
// TODO:发送rev数据
uint8_t *p_rev_msg;
// TsValveMsg *ValveMsg;
// ValveMsg = tmos_msg_allocate(len);
// ValveMsg.data = tmos_msg_allocate(len);
p_rev_msg = tmos_msg_allocate(len + 1);
if ( p_rev_msg )
{
p_rev_msg[0] = len;
tmos_memcpy(&p_rev_msg[1], pValue, len);
int ret = tmos_msg_send(vavle_task_id, p_rev_msg);
if (ret == SUCCESS)
{
logDebug("p_rev_msg send ret = %d", ret);
}
else
{
logError("p_rev_msg send ret = %d", ret);
}
}
else
{
logError("内存不足");
}
#if 0
TsFrameData *HostFrameData = BSP_VAVLE_GetFrameData(newValue, len);
if (HostFrameData != NULL)
{
// logHexDumpAll(&HostFrameData->data[0], HostFrameData->len); // 数据段
// BSP_UART1_TxLoop();
// HR_ProcessData(HostFrameData);
switch (HostFrameData->cmd)
{
case kCmdCfg:
// uint8_t data_buf[64] = {0};
// tmos_memset(data_buf, 0, sizeof(data_buf));
// 处理数据帧
logDebug("kCmdCfg");
break;
case kCmdCloseVavle:
logDebug("kCmdCloseVavle");
// TODO:注意这里
BSP_NeeedReplyCMdFirst();
// EMV_CHARGE
EMV_CHARGE_EN;
logDebug("EMV_CHARGE_EN");
// 开始一个定时event,1s后产生,当前语句只会产生一次event
// 可以在event产生后去开启event,可以是别的task的,也可以是当前task的event
tmos_start_task(vavle_task_id, VAVLE_CLOSE_ACTION_EVT, MS1_TO_SYSTEM_TIME(CHARGE_TIME_MS));
// BSP_VALVE_Generate_ValveResponse(&RawData, kCmdCloseVavle, 1);
// // TODO: 关阀动作
// peripheralChar4Notify((uint8_t *)&RawData.buf[0], RawData.len);
break;
case kCmdOpenVavle:
logDebug("kCmdOpenVavle");
BSP_VALVE_Generate_ValveResponse(&RawData, kCmdOpenVavle, 1);
peripheralChar4Notify((uint8_t *)&RawData.buf[0], RawData.len);
// BSP_UART1_TxLoop();
break;
default:
logError("无效的命令");
// logHexDumpAll(data, len);
break;
}
}
else
{
logError("数据帧解析失败");
}
tmos_msg_deallocate((uint8_t *)HostFrameData);
HostFrameData = NULL;
#endif
logDebug("profile ChangeCB CHAR3.. End");
break;
}
default:
// should not reach here!
break;
}
}
#if 0
// TODO:应用加入广播数据更新部分状态数据
// 动态更新广播数据
// taskID 请求更改广播任务的 ID
// adTypeTRUE 更改广播数据FALSE 更改扫描回复数据
// datalen数据长度
// *pAdvertData数据指针
void Peripheral_UpdateAdvertData(uint8_t adType, uint8_t dataLen, uint8_t *pAdvertData)
{
GAP_UpdateAdvertisingData(Peripheral_TaskID, adType, dataLen, pAdvertData);
}
#include "stdio.h"
#include "stdarg.h"
// TODO:先不弄,后面改广播名,应用加入广播数据更新部分状态数据
void Peripheral_SetMacName(void)
{
uint8_t mac_addr[6];
GetMACAddress(mac_addr);
// 手机APP显示是倒序的[5-0],不是[0-5]
logDebug("MacAddr: %02X:%02X:%02X:%02X:%02X:%02X", mac_addr[0], mac_addr[1]
, mac_addr[2], mac_addr[3], mac_addr[4], mac_addr[5]);
// GAPRole_SetParameter(GAPROLE_ADVERT_DATA, sizeof(advertData), advertData);
uint8_t scan_rsp_data[128];
uint8_t len = 0;
uint8_t name_len;
// complete name
scan_rsp_data[1] = GAP_ADTYPE_LOCAL_NAME_COMPLETE;
name_len = sprintf(&scan_rsp_data[2], "TYQ-%02X:%02X:%02X:%02X:%02X:%02X", mac_addr[0], mac_addr[1]
, mac_addr[2], mac_addr[3], mac_addr[4], mac_addr[5]);
len = name_len + 1;
scan_rsp_data[0] = len;
logDebug("len:%d", len);
// connection interval range
scan_rsp_data[len++] = 0x05;
scan_rsp_data[len++] = LO_UINT16(DEFAULT_DESIRED_MIN_CONN_INTERVAL);
scan_rsp_data[len++] = HI_UINT16(DEFAULT_DESIRED_MIN_CONN_INTERVAL);
scan_rsp_data[len++] = LO_UINT16(DEFAULT_DESIRED_MAX_CONN_INTERVAL);
scan_rsp_data[len++] = HI_UINT16(DEFAULT_DESIRED_MAX_CONN_INTERVAL);
// Tx power level
scan_rsp_data[len++] = 0x02;
scan_rsp_data[len++] = GAP_ADTYPE_POWER_LEVEL;
scan_rsp_data[len] = 0;
logDebug("len:%d", len);
// logDebug("scan_rsp_data:");
logHexDumpAll(scan_rsp_data, len);
// // 更新扫描响应体
GAP_UpdateAdvertisingData(Peripheral_TaskID, FALSE, scan_rsp_data, len);
}
#endif