/********************************** (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_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 #define SBP_PERIODIC_EVT_PERIOD (1600 * 60) // (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 * 5) // 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 * 2) // 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(); 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(); 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(); // BSP_BlockSleep(); // BSP_RequestBoost(); // DelayMs(1); // // ShowLed(); // BEEP_ON; // DelayMs(500); } 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) { gValveData.bat = BSP_ReadVbat(); #if 0 BSP_BlockSleep(); BSP_RequestBoost(); // DelayMs(1); ShowLed(); DelayMs(2); LED_ALL_OFF_DEINIT; // BEEP_OFF_DEINIT; BSP_NoNeedBoost(); BSP_RequestSleep(); #endif // 电压过低就关阀 if (gValveData.bat <= LOW_VABAT_CLOSE_VALUE) { gValveData.switch_status = kClosed; tmos_set_event(vavle_task_id, VAVLE_CLOSE_START_EVT); } else if (gValveData.bat <= LOW_VABAT_ALARM_VALUE) { tmos_set_event(vavle_task_id, VAVLE_LOW_VBAT_ALARM_EVT); } float _humi, _temp; if (BSP_ReadTempHumi(&_humi, &_temp) == 0) { gValveData.temp = (int8_t)_temp; gValveData.humi = (uint8_t)_humi; } else { 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); } /********************************************************************* * @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, ¬i) != SUCCESS) { logError("Noti Err"); GATT_bm_free((gattMsg_t *)¬i, 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 // adType:TRUE 更改广播数据,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