first submission

This commit is contained in:
qiyongshuang
2023-02-01 14:19:13 +08:00
parent d534aad004
commit b79c6ac80d
3711 changed files with 745432 additions and 2 deletions
@@ -0,0 +1,191 @@
/********************************** (C) COPYRIGHT *******************************
* File Name : app_drv_fifo.c
* Author : WCH
* Version : V1.1
* Date : 2022/01/19
* 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.
*******************************************************************************/
#include "app_drv_fifo.h"
static __inline uint16_t fifo_length(app_drv_fifo_t *fifo)
{
uint16_t tmp = fifo->begin;
return fifo->end - tmp;
}
uint16_t app_drv_fifo_length(app_drv_fifo_t *fifo)
{
return fifo_length(fifo);
}
app_drv_fifo_result_t
app_drv_fifo_init(app_drv_fifo_t *fifo, uint8_t *buffer, uint16_t buffer_size)
{
if(buffer_size == 0)
{
return APP_DRV_FIFO_RESULT_LENGTH_ERROR;
}
if(0 != ((buffer_size) & (buffer_size - 1)))
{
return APP_DRV_FIFO_RESULT_LENGTH_ERROR;
}
fifo->begin = 0;
fifo->end = 0;
fifo->data = buffer;
fifo->size = buffer_size;
fifo->size_mask = buffer_size - 1;
return APP_DRV_FIFO_RESULT_SUCCESS;
}
void app_drv_fifo_push(app_drv_fifo_t *fifo, uint8_t data)
{
fifo->data[fifo->end & fifo->size_mask] = data;
fifo->end++;
}
uint8_t app_drv_fifo_pop(app_drv_fifo_t *fifo)
{
uint8_t data = fifo->data[fifo->begin & fifo->size_mask];
fifo->begin++;
return data;
}
void app_drv_fifo_flush(app_drv_fifo_t *fifo)
{
fifo->begin = 0;
fifo->end = 0;
}
bool app_drv_fifo_is_empty(app_drv_fifo_t *fifo)
{
return (fifo->begin == fifo->end);
}
bool app_drv_fifo_is_full(app_drv_fifo_t *fifo)
{
return (fifo_length(fifo) == fifo->size);
}
app_drv_fifo_result_t
app_drv_fifo_write(app_drv_fifo_t *fifo, uint8_t *data, uint16_t *p_write_length)
{
if(fifo == NULL)
{
return APP_DRV_FIFO_RESULT_NULL;
}
if(p_write_length == NULL)
{
return APP_DRV_FIFO_RESULT_NULL;
}
//PRINT("fifo_length = %d\r\n",fifo_length(fifo));
const uint16_t available_count = fifo->size - fifo_length(fifo);
const uint16_t requested_len = (*p_write_length);
uint16_t index = 0;
uint16_t write_size = MIN(requested_len, available_count);
//PRINT("available_count %d\r\n",available_count);
// Check if the FIFO is FULL.
if(available_count == 0)
{
return APP_DRV_FIFO_RESULT_NOT_MEM;
}
// Check if application has requested only the size.
if(data == NULL)
{
return APP_DRV_FIFO_RESULT_SUCCESS;
}
for(index = 0; index < write_size; index++)
{
//push
fifo->data[fifo->end & fifo->size_mask] = data[index];
fifo->end++;
}
(*p_write_length) = write_size;
return APP_DRV_FIFO_RESULT_SUCCESS;
}
app_drv_fifo_result_t
app_drv_fifo_write_from_same_addr(app_drv_fifo_t *fifo, uint8_t *data, uint16_t write_length)
{
if(fifo == NULL)
{
return APP_DRV_FIFO_RESULT_NULL;
}
const uint16_t available_count = fifo->size_mask - fifo_length(fifo) + 1;
const uint16_t requested_len = (write_length);
uint16_t index = 0;
uint16_t write_size = MIN(requested_len, available_count);
// Check if the FIFO is FULL.
if(available_count == 0)
{
return APP_DRV_FIFO_RESULT_NOT_MEM;
}
for(index = 0; index < write_size; index++)
{
//push
fifo->data[fifo->end & fifo->size_mask] = data[0];
fifo->end++;
}
return APP_DRV_FIFO_RESULT_SUCCESS;
}
app_drv_fifo_result_t
app_drv_fifo_read(app_drv_fifo_t *fifo, uint8_t *data, uint16_t *p_read_length)
{
if(fifo == NULL)
{
return APP_DRV_FIFO_RESULT_NULL;
}
if(p_read_length == NULL)
{
return APP_DRV_FIFO_RESULT_NULL;
}
const uint16_t byte_count = fifo_length(fifo);
const uint16_t requested_len = (*p_read_length);
uint32_t index = 0;
uint32_t read_size = MIN(requested_len, byte_count);
if(byte_count == 0)
{
return APP_DRV_FIFO_RESULT_NOT_FOUND;
}
//PRINT("read size = %d,byte_count = %d\r\n",read_size,byte_count);
for(index = 0; index < read_size; index++)
{
//pop
data[index] = fifo->data[fifo->begin & fifo->size_mask];
fifo->begin++;
}
(*p_read_length) = read_size;
return APP_DRV_FIFO_RESULT_SUCCESS;
}
app_drv_fifo_result_t
app_drv_fifo_read_to_same_addr(app_drv_fifo_t *fifo, uint8_t *data, uint16_t read_length)
{
if(fifo == NULL)
{
return APP_DRV_FIFO_RESULT_NULL;
}
const uint16_t byte_count = fifo_length(fifo);
const uint16_t requested_len = (read_length);
uint32_t index = 0;
uint32_t read_size = MIN(requested_len, byte_count);
for(index = 0; index < read_size; index++)
{
//pop
data[0] = fifo->data[fifo->begin & fifo->size_mask];
fifo->begin++;
}
return APP_DRV_FIFO_RESULT_SUCCESS;
}
@@ -0,0 +1,133 @@
/********************************** (C) COPYRIGHT *******************************
* File Name : app_drv_fifo.h
* Author : WCH
* Version : V1.1
* Date : 2022/01/19
* 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.
*******************************************************************************/
#ifndef __APP_DRV_FIFO_H__
#define __APP_DRV_FIFO_H__
#include <stdbool.h>
#include <stdint.h>
#ifndef BV
#define BV(n) (1 << (n))
#endif
#ifndef BF
#define BF(x, b, s) (((x) & (b)) >> (s))
#endif
#ifndef MIN
#define MIN(n, m) (((n) < (m)) ? (n) : (m))
#endif
#ifndef MAX
#define MAX(n, m) (((n) < (m)) ? (m) : (n))
#endif
#ifndef ABS
#define ABS(n) (((n) < 0) ? -(n) : (n))
#endif
typedef enum
{
APP_DRV_FIFO_RESULT_SUCCESS = 0,
APP_DRV_FIFO_RESULT_LENGTH_ERROR,
APP_DRV_FIFO_RESULT_NOT_FOUND,
APP_DRV_FIFO_RESULT_NOT_MEM,
APP_DRV_FIFO_RESULT_NULL,
} app_drv_fifo_result_t;
#ifndef NULL
#define NULL 0
#endif
/*!
* FIFO structure
*/
typedef struct Fifo_s
{
uint16_t begin;
uint16_t end;
uint8_t *data;
uint16_t size;
uint16_t size_mask;
} app_drv_fifo_t;
//__inline uint16_t app_drv_fifo_length(app_drv_fifo_t *fifo);
uint16_t app_drv_fifo_length(app_drv_fifo_t *fifo);
/*!
* Initializes the FIFO structure
*
* \param [IN] fifo Pointer to the FIFO object
* \param [IN] buffer Buffer to be used as FIFO
* \param [IN] size size of the buffer
*/
app_drv_fifo_result_t
app_drv_fifo_init(app_drv_fifo_t *fifo, uint8_t *buffer, uint16_t buffer_size);
/*!
* Pushes data to the FIFO
*
* \param [IN] fifo Pointer to the FIFO object
* \param [IN] data data to be pushed into the FIFO
*/
void app_drv_fifo_push(app_drv_fifo_t *fifo, uint8_t data);
/*!
* Pops data from the FIFO
*
* \param [IN] fifo Pointer to the FIFO object
* \retval data data popped from the FIFO
*/
uint8_t app_drv_fifo_pop(app_drv_fifo_t *fifo);
/*!
* Flushes the FIFO
*
* \param [IN] fifo Pointer to the FIFO object
*/
void app_drv_fifo_flush(app_drv_fifo_t *fifo);
/*!
* Checks if the FIFO is empty
*
* \param [IN] fifo Pointer to the FIFO object
* \retval isEmpty true: FIFO is empty, false FIFO is not empty
*/
bool app_drv_fifo_is_empty(app_drv_fifo_t *fifo);
/*!
* Checks if the FIFO is full
*
* \param [IN] fifo Pointer to the FIFO object
* \retval isFull true: FIFO is full, false FIFO is not full
*/
bool app_drv_fifo_is_full(app_drv_fifo_t *fifo);
app_drv_fifo_result_t
app_drv_fifo_write(app_drv_fifo_t *fifo, uint8_t *data,
uint16_t *p_write_length);
app_drv_fifo_result_t
app_drv_fifo_write_from_same_addr(app_drv_fifo_t *fifo, uint8_t *data,
uint16_t write_length);
app_drv_fifo_result_t
app_drv_fifo_read(app_drv_fifo_t *fifo, uint8_t *data, uint16_t *p_read_length);
app_drv_fifo_result_t
app_drv_fifo_read_to_same_addr(app_drv_fifo_t *fifo, uint8_t *data,
uint16_t read_length);
#endif // __APP_DRV_FIFO_H__
@@ -0,0 +1,379 @@
/********************************** (C) COPYRIGHT *******************************
* File Name : ble_uart_service.c
* Author : WCH
* Version : V1.1
* Date : 2022/01/19
* 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 "gattprofile.h"
#include "stdint.h"
#include "ble_uart_service.h"
/*********************************************************************
* MACROS
*/
/*********************************************************************
* CONSTANTS
*/
#define SERVAPP_NUM_ATTR_SUPPORTED 7
#define RAWPASS_TX_VALUE_HANDLE 4
#define RAWPASS_RX_VALUE_HANDLE 2
/*********************************************************************
* TYPEDEFS
*/
/*********************************************************************
* GLOBAL VARIABLES
*/
////ble_uart GATT Profile Service UUID
//const uint8_t ble_uart_ServiceUUID[ATT_UUID_SIZE] =
//{0x55, 0xe4,0x05,0xd2,0xaf,0x9f,0xa9,0x8f,0xe5,0x4a,0x7d,0xfe,0x43,0x53,0x53,0x49};
//// Characteristic rx uuid
//const uint8_t ble_uart_RxCharUUID[ATT_UUID_SIZE] =
//{0xb3,0x9b,0x72,0x34,0xbe,0xec, 0xd4,0xa8,0xf4,0x43,0x41,0x88,0x43,0x53,0x53,0x49};
//// Characteristic tx uuid
//const uint8_t ble_uart_TxCharUUID[ATT_UUID_SIZE] =
//{0x16,0x96,0x24,0x47,0xc6,0x23, 0x61,0xba,0xd9,0x4b,0x4d,0x1e,0x43,0x53,0x53,0x49};
// ble_uart GATT Profile Service UUID
const uint8_t ble_uart_ServiceUUID[ATT_UUID_SIZE] =
{0x9F, 0xCA, 0xDC, 0x24, 0x0E, 0xE5, 0xA9, 0xE0, 0x93, 0xF3, 0xA3, 0xB5, 0x01, 0x00, 0x40, 0x6E};
// Characteristic rx uuid
const uint8_t ble_uart_RxCharUUID[ATT_UUID_SIZE] =
{0x9F, 0xCA, 0xDC, 0x24, 0x0E, 0xE5, 0xA9, 0xE0, 0x93, 0xF3, 0xA3, 0xB5, 0x02, 0x00, 0x40, 0x6E};
// Characteristic tx uuid
const uint8_t ble_uart_TxCharUUID[ATT_UUID_SIZE] =
{0x9F, 0xCA, 0xDC, 0x24, 0x0E, 0xE5, 0xA9, 0xE0, 0x93, 0xF3, 0xA3, 0xB5, 0x03, 0x00, 0x40, 0x6E};
/*********************************************************************
* EXTERNAL VARIABLES
*/
/*********************************************************************
* EXTERNAL FUNCTIONS
*/
/*********************************************************************
* LOCAL VARIABLES
*/
static ble_uart_ProfileChangeCB_t ble_uart_AppCBs = NULL;
/*********************************************************************
* Profile Attributes - variables
*/
// Profile Service attribute
static const gattAttrType_t ble_uart_Service = {ATT_UUID_SIZE, ble_uart_ServiceUUID};
// Profile Characteristic 1 Properties
//static uint8_t ble_uart_RxCharProps = GATT_PROP_WRITE_NO_RSP| GATT_PROP_WRITE;
static uint8_t ble_uart_RxCharProps = GATT_PROP_WRITE_NO_RSP;
// Characteristic 1 Value
static uint8_t ble_uart_RxCharValue[BLE_UART_RX_BUFF_SIZE];
//static uint8_t ble_uart_RxCharValue[1];
// Profile Characteristic 2 Properties
//static uint8_t ble_uart_TxCharProps = GATT_PROP_NOTIFY| GATT_PROP_INDICATE;
static uint8_t ble_uart_TxCharProps = GATT_PROP_NOTIFY;
// Characteristic 2 Value
static uint8_t ble_uart_TxCharValue = 0;
// Simple Profile Characteristic 2 User Description
static gattCharCfg_t ble_uart_TxCCCD[4];
/*********************************************************************
* Profile Attributes - Table
*/
static gattAttribute_t ble_uart_ProfileAttrTbl[] = {
// Simple Profile Service
{
{ATT_BT_UUID_SIZE, primaryServiceUUID}, /* type */
GATT_PERMIT_READ, /* permissions */
0, /* handle */
(uint8_t *)&ble_uart_Service /* pValue */
},
// Characteristic 1 Declaration
{
{ATT_BT_UUID_SIZE, characterUUID},
GATT_PERMIT_READ,
0,
&ble_uart_RxCharProps},
// Characteristic Value 1
{
{ATT_UUID_SIZE, ble_uart_RxCharUUID},
GATT_PERMIT_WRITE,
0,
&ble_uart_RxCharValue[0]},
// Characteristic 2 Declaration
{
{ATT_BT_UUID_SIZE, characterUUID},
GATT_PERMIT_READ,
0,
&ble_uart_TxCharProps},
// Characteristic Value 2
{
{ATT_UUID_SIZE, ble_uart_TxCharUUID},
0,
0,
(uint8_t *)&ble_uart_TxCharValue},
// Characteristic 2 User Description
{
{ATT_BT_UUID_SIZE, clientCharCfgUUID},
GATT_PERMIT_READ | GATT_PERMIT_WRITE,
0,
(uint8_t *)ble_uart_TxCCCD},
};
/*********************************************************************
* LOCAL FUNCTIONS
*/
static bStatus_t ble_uart_ReadAttrCB(uint16_t connHandle, gattAttribute_t *pAttr,
uint8_t *pValue, uint16_t *pLen, uint16_t offset, uint16_t maxLen, uint8_t method);
static bStatus_t ble_uart_WriteAttrCB(uint16_t connHandle, gattAttribute_t *pAttr,
uint8_t *pValue, uint16_t len, uint16_t offset, uint8_t method);
static void ble_uart_HandleConnStatusCB(uint16_t connHandle, uint8_t changeType);
/*********************************************************************
* PROFILE CALLBACKS
*/
// Simple Profile Service Callbacks
gattServiceCBs_t ble_uart_ProfileCBs = {
ble_uart_ReadAttrCB, // Read callback function pointer
ble_uart_WriteAttrCB, // Write callback function pointer
NULL // Authorization callback function pointer
};
/*********************************************************************
* PUBLIC FUNCTIONS
*/
/*********************************************************************
* @fn ble_uart_AddService
*
* @brief Initializes the Simple Profile service by registering
* GATT attributes with the GATT server.
*
* @param services - services to add. This is a bit map and can
* contain more than one service.
*
* @return Success or Failure
*/
bStatus_t ble_uart_add_service(ble_uart_ProfileChangeCB_t cb)
{
uint8_t status = SUCCESS;
GATTServApp_InitCharCfg(INVALID_CONNHANDLE, ble_uart_TxCCCD);
// Register with Link DB to receive link status change callback
linkDB_Register(ble_uart_HandleConnStatusCB);
// ble_uart_TxCCCD.connHandle = INVALID_CONNHANDLE;
// ble_uart_TxCCCD.value = 0;
// Register GATT attribute list and CBs with GATT Server App
status = GATTServApp_RegisterService(ble_uart_ProfileAttrTbl,
GATT_NUM_ATTRS(ble_uart_ProfileAttrTbl),
GATT_MAX_ENCRYPT_KEY_SIZE,
&ble_uart_ProfileCBs);
if(status != SUCCESS)
PRINT("Add ble uart service failed!\n");
ble_uart_AppCBs = cb;
return (status);
}
/*********************************************************************
* @fn ble_uart_ReadAttrCB
*
* @brief Read an attribute.
*
* @param connHandle - connection message was received on
* @param pAttr - pointer to attribute
* @param pValue - pointer to data to be read
* @param pLen - length of data to be read
* @param offset - offset of the first octet to be read
* @param maxLen - maximum length of data to be read
*
* @return Success or Failure
*/
static bStatus_t ble_uart_ReadAttrCB(uint16_t connHandle, gattAttribute_t *pAttr,
uint8_t *pValue, uint16_t *pLen, uint16_t offset, uint16_t maxLen, uint8_t method)
{
bStatus_t status = SUCCESS;
PRINT("ReadAttrCB\n");
// Make sure it's not a blob operation (no attributes in the profile are long)
if(pAttr->type.len == ATT_BT_UUID_SIZE)
{
// 16-bit UUID
uint16_t uuid = BUILD_UINT16(pAttr->type.uuid[0], pAttr->type.uuid[1]);
if(uuid == GATT_CLIENT_CHAR_CFG_UUID)
{
*pLen = 2;
tmos_memcpy(pValue, pAttr->pValue, 2);
}
}
else
{
if(tmos_memcmp(pAttr->type.uuid, ble_uart_TxCharUUID, 16))
{
*pLen = 1;
pValue[0] = '1';
}
else if(tmos_memcmp(pAttr->type.uuid, ble_uart_RxCharUUID, 16))
{
PRINT("read tx char\n");
}
}
return (status);
}
/*********************************************************************
* @fn simpleProfile_WriteAttrCB
*
* @brief Validate attribute data prior to a write operation
*
* @param connHandle - connection message was received on
* @param pAttr - pointer to attribute
* @param pValue - pointer to data to be written
* @param len - length of data
* @param offset - offset of the first octet to be written
*
* @return Success or Failure
*/
static bStatus_t ble_uart_WriteAttrCB(uint16_t connHandle, gattAttribute_t *pAttr,
uint8_t *pValue, uint16_t len, uint16_t offset, uint8_t method)
{
bStatus_t status = SUCCESS;
//uint8_t notifyApp = 0xFF;
// If attribute permissions require authorization to write, return error
if(gattPermitAuthorWrite(pAttr->permissions))
{
// Insufficient authorization
return (ATT_ERR_INSUFFICIENT_AUTHOR);
}
if(pAttr->type.len == ATT_BT_UUID_SIZE)
{
// 16-bit UUID
uint16_t uuid = BUILD_UINT16(pAttr->type.uuid[0], pAttr->type.uuid[1]);
if(uuid == GATT_CLIENT_CHAR_CFG_UUID)
{
status = GATTServApp_ProcessCCCWriteReq(connHandle, pAttr, pValue, len,
offset, GATT_CLIENT_CFG_NOTIFY);
if(status == SUCCESS && ble_uart_AppCBs)
{
uint16_t charCfg = BUILD_UINT16(pValue[0], pValue[1]);
ble_uart_evt_t evt;
//PRINT("CCCD set: [%d]\n", charCfg);
evt.type = (charCfg == GATT_CFG_NO_OPERATION) ? BLE_UART_EVT_TX_NOTI_DISABLED : BLE_UART_EVT_TX_NOTI_ENABLED;
ble_uart_AppCBs(connHandle, &evt);
}
}
}
else
{
// 128-bit UUID
if(pAttr->handle == ble_uart_ProfileAttrTbl[RAWPASS_RX_VALUE_HANDLE].handle)
{
if(ble_uart_AppCBs)
{
ble_uart_evt_t evt;
evt.type = BLE_UART_EVT_BLE_DATA_RECIEVED;
evt.data.length = (uint16_t)len;
evt.data.p_data = pValue;
ble_uart_AppCBs(connHandle, &evt);
}
}
}
return (status);
}
/*********************************************************************
* @fn simpleProfile_HandleConnStatusCB
*
* @brief Simple Profile link status change handler function.
*
* @param connHandle - connection handle
* @param changeType - type of change
*
* @return none
*/
static void ble_uart_HandleConnStatusCB(uint16_t connHandle, uint8_t changeType)
{
// Make sure this is not loopback connection
if(connHandle != LOOPBACK_CONNHANDLE)
{
// Reset Client Char Config if connection has dropped
if((changeType == LINKDB_STATUS_UPDATE_REMOVED) ||
((changeType == LINKDB_STATUS_UPDATE_STATEFLAGS) &&
(!linkDB_Up(connHandle))))
{
//ble_uart_TxCCCD[0].value = 0;
GATTServApp_InitCharCfg(connHandle, ble_uart_TxCCCD);
//PRINT("clear client configuration\n");
}
}
}
uint8_t ble_uart_notify_is_ready(uint16_t connHandle)
{
return (GATT_CLIENT_CFG_NOTIFY == GATTServApp_ReadCharCfg(connHandle, ble_uart_TxCCCD));
}
/*********************************************************************
* @fn BloodPressure_IMeasNotify
*
* @brief Send a notification containing a bloodPressure
* measurement.
*
* @param connHandle - connection handle
* @param pNoti - pointer to notification structure
*
* @return Success or Failure
*/
bStatus_t ble_uart_notify(uint16_t connHandle, attHandleValueNoti_t *pNoti, uint8_t taskId)
{
//uint16_t value = ble_uart_TxCCCD[0].value;
uint16_t value = GATTServApp_ReadCharCfg(connHandle, ble_uart_TxCCCD);
// If notifications enabled
if(value & GATT_CLIENT_CFG_NOTIFY)
{
// Set the handle
pNoti->handle = ble_uart_ProfileAttrTbl[RAWPASS_TX_VALUE_HANDLE].handle;
// Send the Indication
return GATT_Notification(connHandle, pNoti, FALSE);
}
return bleIncorrectMode;
}
/*********************************************************************
*********************************************************************/
@@ -0,0 +1,70 @@
/********************************** (C) COPYRIGHT *******************************
* File Name : simpleGATTprofile.h
* Author : WCH
* Version : V1.1
* Date : 2022/01/19
* 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.
*******************************************************************************/
#ifndef _BLE_UART_SERVICE_H
#define _BLE_UART_SERVICE_H
#ifdef __cplusplus
extern "C" {
#endif
//#include "att.h"
#include "stdint.h"
#define BLE_UART_RX_BUFF_SIZE 1
typedef enum
{
BLE_UART_EVT_TX_NOTI_DISABLED = 1,
BLE_UART_EVT_TX_NOTI_ENABLED,
BLE_UART_EVT_BLE_DATA_RECIEVED,
} ble_uart_evt_type_t;
typedef struct
{
uint8_t const *p_data; /**< A pointer to the buffer with received data. */
uint16_t length; /**< Length of received data. */
} ble_uart_evt_rx_data_t;
typedef struct
{
ble_uart_evt_type_t type;
ble_uart_evt_rx_data_t data;
} ble_uart_evt_t;
typedef void (*ble_uart_ProfileChangeCB_t)(uint16_t connection_handle, ble_uart_evt_t *p_evt);
/*********************************************************************
* API FUNCTIONS
*/
/*
* ble_uart_AddService- Initializes the raw pass GATT Profile service by registering
* GATT attributes with the GATT server.
*
* @param services - services to add. This is a bit map and can
* contain more than one service.
*/
extern bStatus_t ble_uart_add_service(ble_uart_ProfileChangeCB_t cb);
extern uint8_t ble_uart_notify_is_ready(uint16_t connHandle);
extern bStatus_t ble_uart_notify(uint16_t connHandle, attHandleValueNoti_t *pNoti, uint8_t taskId);
/*********************************************************************
*********************************************************************/
#ifdef __cplusplus
}
#endif
#endif /* _BLE_UART_SERVICE_H */
@@ -0,0 +1,381 @@
/********************************** (C) COPYRIGHT *******************************
* File Name : ble_uart_service_16bit_char.c
* Author : WCH
* Version : V1.1
* Date : 2022/01/19
* 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 "gattprofile.h"
#include "stdint.h"
#include "ble_uart_service.h"
/*********************************************************************
* MACROS
*/
/*********************************************************************
* CONSTANTS
*/
#define SERVAPP_NUM_ATTR_SUPPORTED 7
#define RAWPASS_TX_VALUE_HANDLE 2
#define RAWPASS_RX_VALUE_HANDLE 5
/*********************************************************************
* TYPEDEFS
*/
/*********************************************************************
* GLOBAL VARIABLES
*/
// ble_uart GATT Profile Service UUID
const uint8_t ble_uart_ServiceUUID[ATT_BT_UUID_SIZE] =
{0xf0, 0xff};
// Characteristic rx uuid
const uint8_t ble_uart_RxCharUUID[ATT_BT_UUID_SIZE] =
{0xf2, 0xff};
// Characteristic tx uuid
const uint8_t ble_uart_TxCharUUID[ATT_BT_UUID_SIZE] =
{0xf1, 0xff};
/*********************************************************************
* EXTERNAL VARIABLES
*/
/*********************************************************************
* EXTERNAL FUNCTIONS
*/
/*********************************************************************
* LOCAL VARIABLES
*/
static ble_uart_ProfileChangeCB_t ble_uart_AppCBs = NULL;
/*********************************************************************
* Profile Attributes - variables
*/
// Profile Service attribute
static const gattAttrType_t ble_uart_Service = {ATT_BT_UUID_SIZE, ble_uart_ServiceUUID};
// Profile Characteristic 1 Properties
//static uint8_t ble_uart_RxCharProps = GATT_PROP_WRITE_NO_RSP| GATT_PROP_WRITE;
static uint8_t ble_uart_RxCharProps = GATT_PROP_WRITE_NO_RSP | GATT_PROP_WRITE;
// Characteristic 1 Value
static uint8_t ble_uart_RxCharValue[BLE_UART_RX_BUFF_SIZE];
//static uint8_t ble_uart_RxCharValue[1];
// Profile Characteristic 2 Properties
//static uint8_t ble_uart_TxCharProps = GATT_PROP_NOTIFY| GATT_PROP_INDICATE;
static uint8_t ble_uart_TxCharProps = GATT_PROP_NOTIFY;
// Characteristic 2 Value
static uint8_t ble_uart_TxCharValue = 0;
// Simple Profile Characteristic 2 User Description
static gattCharCfg_t ble_uart_TxCCCD[4];
/*********************************************************************
* Profile Attributes - Table
*/
static gattAttribute_t ble_uart_ProfileAttrTbl[] = {
// Simple Profile Service
{
{ATT_BT_UUID_SIZE, primaryServiceUUID}, /* type */
GATT_PERMIT_READ, /* permissions */
0, /* handle */
(uint8_t *)&ble_uart_Service /* pValue */
},
// Characteristic 2 Declaration
{
{ATT_BT_UUID_SIZE, characterUUID},
GATT_PERMIT_READ,
0,
&ble_uart_TxCharProps},
// Characteristic Value 2
{
{ATT_BT_UUID_SIZE, ble_uart_TxCharUUID},
0,
0,
(uint8_t *)&ble_uart_TxCharValue},
// Characteristic 2 User Description
{
{ATT_BT_UUID_SIZE, clientCharCfgUUID},
GATT_PERMIT_READ | GATT_PERMIT_WRITE,
0,
(uint8_t *)ble_uart_TxCCCD},
// Characteristic 1 Declaration
{
{ATT_BT_UUID_SIZE, characterUUID},
GATT_PERMIT_READ,
0,
&ble_uart_RxCharProps},
// Characteristic Value 1
{
{ATT_BT_UUID_SIZE, ble_uart_RxCharUUID},
GATT_PERMIT_WRITE,
0,
&ble_uart_RxCharValue[0]},
};
/*********************************************************************
* LOCAL FUNCTIONS
*/
static bStatus_t ble_uart_ReadAttrCB(uint16_t connHandle, gattAttribute_t *pAttr,
uint8_t *pValue, uint16_t *pLen, uint16_t offset, uint16_t maxLen, uint8_t method);
static bStatus_t ble_uart_WriteAttrCB(uint16_t connHandle, gattAttribute_t *pAttr,
uint8_t *pValue, uint16_t len, uint16_t offset, uint8_t method);
static void ble_uart_HandleConnStatusCB(uint16_t connHandle, uint8_t changeType);
/*********************************************************************
* PROFILE CALLBACKS
*/
// Simple Profile Service Callbacks
gattServiceCBs_t ble_uart_ProfileCBs = {
ble_uart_ReadAttrCB, // Read callback function pointer
ble_uart_WriteAttrCB, // Write callback function pointer
NULL // Authorization callback function pointer
};
/*********************************************************************
* PUBLIC FUNCTIONS
*/
/*********************************************************************
* @fn ble_uart_AddService
*
* @brief Initializes the Simple Profile service by registering
* GATT attributes with the GATT server.
*
* @param services - services to add. This is a bit map and can
* contain more than one service.
*
* @return Success or Failure
*/
bStatus_t ble_uart_add_service(ble_uart_ProfileChangeCB_t cb)
{
uint8_t status = SUCCESS;
GATTServApp_InitCharCfg(INVALID_CONNHANDLE, ble_uart_TxCCCD);
// Register with Link DB to receive link status change callback
linkDB_Register(ble_uart_HandleConnStatusCB);
// ble_uart_TxCCCD.connHandle = INVALID_CONNHANDLE;
// ble_uart_TxCCCD.value = 0;
// Register GATT attribute list and CBs with GATT Server App
status = GATTServApp_RegisterService(ble_uart_ProfileAttrTbl,
GATT_NUM_ATTRS(ble_uart_ProfileAttrTbl),
GATT_MAX_ENCRYPT_KEY_SIZE,
&ble_uart_ProfileCBs);
if(status != SUCCESS)
PRINT("Add ble uart service failed!\n");
ble_uart_AppCBs = cb;
return (status);
}
/*********************************************************************
* @fn ble_uart_ReadAttrCB
*
* @brief Read an attribute.
*
* @param connHandle - connection message was received on
* @param pAttr - pointer to attribute
* @param pValue - pointer to data to be read
* @param pLen - length of data to be read
* @param offset - offset of the first octet to be read
* @param maxLen - maximum length of data to be read
*
* @return Success or Failure
*/
static bStatus_t ble_uart_ReadAttrCB(uint16_t connHandle, gattAttribute_t *pAttr,
uint8_t *pValue, uint16_t *pLen, uint16_t offset, uint16_t maxLen, uint8_t method)
{
bStatus_t status = SUCCESS;
PRINT("ReadAttrCB\n");
// Make sure it's not a blob operation (no attributes in the profile are long)
if(pAttr->type.len == ATT_BT_UUID_SIZE)
{
// 16-bit UUID
uint16_t uuid = BUILD_UINT16(pAttr->type.uuid[0], pAttr->type.uuid[1]);
if(uuid == GATT_CLIENT_CHAR_CFG_UUID)
{
*pLen = 2;
tmos_memcpy(pValue, pAttr->pValue, 2);
}
}
// else
// {
// if(!tmos_memcmp(pAttr->type.uuid, ble_uart_TxCharUUID, 16))
// {
// *pLen = 1;
// pValue[0] = '1';
// }
// else if(!tmos_memcmp(pAttr->type.uuid, ble_uart_RxCharUUID, 16))
// {
// PRINT("read tx char\n");
// }
// }
return (status);
}
/*********************************************************************
* @fn simpleProfile_WriteAttrCB
*
* @brief Validate attribute data prior to a write operation
*
* @param connHandle - connection message was received on
* @param pAttr - pointer to attribute
* @param pValue - pointer to data to be written
* @param len - length of data
* @param offset - offset of the first octet to be written
*
* @return Success or Failure
*/
static bStatus_t ble_uart_WriteAttrCB(uint16_t connHandle, gattAttribute_t *pAttr,
uint8_t *pValue, uint16_t len, uint16_t offset, uint8_t method)
{
bStatus_t status = SUCCESS;
//uint8_t notifyApp = 0xFF;
// If attribute permissions require authorization to write, return error
if(gattPermitAuthorWrite(pAttr->permissions))
{
// Insufficient authorization
return (ATT_ERR_INSUFFICIENT_AUTHOR);
}
if(pAttr->type.len == ATT_BT_UUID_SIZE)
{
// 16-bit UUID
uint16_t uuid = BUILD_UINT16(pAttr->type.uuid[0], pAttr->type.uuid[1]);
if(uuid == GATT_CLIENT_CHAR_CFG_UUID)
{
status = GATTServApp_ProcessCCCWriteReq(connHandle, pAttr, pValue, len,
offset, GATT_CLIENT_CFG_NOTIFY);
if(status == SUCCESS && ble_uart_AppCBs)
{
uint16_t charCfg = BUILD_UINT16(pValue[0], pValue[1]);
ble_uart_evt_t evt;
//PRINT("CCCD set: [%d]\n", charCfg);
evt.type = (charCfg == GATT_CFG_NO_OPERATION) ? BLE_UART_EVT_TX_NOTI_DISABLED : BLE_UART_EVT_TX_NOTI_ENABLED;
ble_uart_AppCBs(connHandle, &evt);
}
}
// UUID
if(pAttr->handle == ble_uart_ProfileAttrTbl[RAWPASS_RX_VALUE_HANDLE].handle)
{
if(ble_uart_AppCBs)
{
ble_uart_evt_t evt;
evt.type = BLE_UART_EVT_BLE_DATA_RECIEVED;
evt.data.length = (uint16_t)len;
evt.data.p_data = pValue;
ble_uart_AppCBs(connHandle, &evt);
}
}
}
// else
// {
// // 128-bit UUID
// if(pAttr->handle == ble_uart_ProfileAttrTbl[RAWPASS_RX_VALUE_HANDLE].handle)
// {
// if(ble_uart_AppCBs) {
// ble_uart_evt_t evt;
// evt.type = BLE_UART_EVT_BLE_DATA_RECIEVED;
// evt.data.length = (uint16_t)len;
// evt.data.p_data = pValue;
// ble_uart_AppCBs(connHandle,&evt);
// }
// }
// }
return (status);
}
/*********************************************************************
* @fn simpleProfile_HandleConnStatusCB
*
* @brief Simple Profile link status change handler function.
*
* @param connHandle - connection handle
* @param changeType - type of change
*
* @return none
*/
static void ble_uart_HandleConnStatusCB(uint16_t connHandle, uint8_t changeType)
{
// Make sure this is not loopback connection
if(connHandle != LOOPBACK_CONNHANDLE)
{
// Reset Client Char Config if connection has dropped
if((changeType == LINKDB_STATUS_UPDATE_REMOVED) ||
((changeType == LINKDB_STATUS_UPDATE_STATEFLAGS) &&
(!linkDB_Up(connHandle))))
{
//ble_uart_TxCCCD[0].value = 0;
GATTServApp_InitCharCfg(connHandle, ble_uart_TxCCCD);
//PRINT("clear client configuration\n");
}
}
}
uint8_t ble_uart_notify_is_ready(uint16_t connHandle)
{
return (GATT_CLIENT_CFG_NOTIFY == GATTServApp_ReadCharCfg(connHandle, ble_uart_TxCCCD));
}
/*********************************************************************
* @fn BloodPressure_IMeasNotify
*
* @brief Send a notification containing a bloodPressure
* measurement.
*
* @param connHandle - connection handle
* @param pNoti - pointer to notification structure
*
* @return Success or Failure
*/
bStatus_t ble_uart_notify(uint16_t connHandle, attHandleValueNoti_t *pNoti, uint8_t taskId)
{
//uint16_t value = ble_uart_TxCCCD[0].value;
uint16_t value = GATTServApp_ReadCharCfg(connHandle, ble_uart_TxCCCD);
// If notifications enabled
if(value & GATT_CLIENT_CFG_NOTIFY)
{
// Set the handle
pNoti->handle = ble_uart_ProfileAttrTbl[RAWPASS_TX_VALUE_HANDLE].handle;
// Send the Indication
return GATT_Notification(connHandle, pNoti, FALSE);
}
return bleIncorrectMode;
}
/*********************************************************************
*********************************************************************/
@@ -0,0 +1,395 @@
/********************************** (C) COPYRIGHT *******************************
* File Name : ble_uart_service_same_16bit_char.c
* Author : WCH
* Version : V1.1
* Date : 2022/01/19
* 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 "gattprofile.h"
#include "stdint.h"
#include "ble_uart_service.h"
/*********************************************************************
* MACROS
*/
/*********************************************************************
* CONSTANTS
*/
#define SERVAPP_NUM_ATTR_SUPPORTED 7
#define RAWPASS_TX_VALUE_HANDLE 2
//#define RAWPASS_RX_VALUE_HANDLE 2
/*********************************************************************
* TYPEDEFS
*/
/*********************************************************************
* GLOBAL VARIABLES
*/
////ble_uart GATT Profile Service UUID
//const uint8_t ble_uart_ServiceUUID[ATT_UUID_SIZE] =
//{0x55, 0xe4,0x05,0xd2,0xaf,0x9f,0xa9,0x8f,0xe5,0x4a,0x7d,0xfe,0x43,0x53,0x53,0x49};
//// Characteristic rx uuid
//const uint8_t ble_uart_RxCharUUID[ATT_UUID_SIZE] =
//{0xb3,0x9b,0x72,0x34,0xbe,0xec, 0xd4,0xa8,0xf4,0x43,0x41,0x88,0x43,0x53,0x53,0x49};
//// Characteristic tx uuid
//const uint8_t ble_uart_TxCharUUID[ATT_UUID_SIZE] =
//{0x16,0x96,0x24,0x47,0xc6,0x23, 0x61,0xba,0xd9,0x4b,0x4d,0x1e,0x43,0x53,0x53,0x49};
// ble_uart GATT Profile Service UUID
const uint8_t ble_uart_ServiceUUID[ATT_BT_UUID_SIZE] =
{0xf0, 0xff};
// Characteristic rx uuid
//const uint8_t ble_uart_RxCharUUID[ATT_UUID_SIZE] =
//{0x9E, 0xCA, 0xDC, 0x24, 0x0E, 0xE5, 0xA9, 0xE0, 0x93, 0xF3, 0xA3, 0xB5, 0x02, 0x00, 0x40, 0x6E};
// Characteristic tx uuid
const uint8_t ble_uart_TxCharUUID[ATT_BT_UUID_SIZE] =
{0xf1, 0xff};
/*********************************************************************
* EXTERNAL VARIABLES
*/
/*********************************************************************
* EXTERNAL FUNCTIONS
*/
/*********************************************************************
* LOCAL VARIABLES
*/
static ble_uart_ProfileChangeCB_t ble_uart_AppCBs = NULL;
/*********************************************************************
* Profile Attributes - variables
*/
// Profile Service attribute
static const gattAttrType_t ble_uart_Service = {ATT_BT_UUID_SIZE, ble_uart_ServiceUUID};
// Profile Characteristic 1 Properties
//static uint8_t ble_uart_RxCharProps = GATT_PROP_WRITE_NO_RSP| GATT_PROP_WRITE;
//static uint8_t ble_uart_RxCharProps = GATT_PROP_WRITE_NO_RSP;
// Characteristic 1 Value
static uint8_t ble_uart_RxCharValue[BLE_UART_RX_BUFF_SIZE];
//static uint8_t ble_uart_RxCharValue[1];
// Profile Characteristic 2 Properties
//static uint8_t ble_uart_TxCharProps = GATT_PROP_NOTIFY| GATT_PROP_INDICATE;
static uint8_t ble_uart_TxCharProps = GATT_PROP_WRITE_NO_RSP | GATT_PROP_NOTIFY | GATT_PROP_READ;
// Characteristic 2 Value
static uint8_t ble_uart_TxCharValue = 0;
// Simple Profile Characteristic 2 User Description
static gattCharCfg_t ble_uart_TxCCCD[4];
/*********************************************************************
* Profile Attributes - Table
*/
static gattAttribute_t ble_uart_ProfileAttrTbl[] = {
// Simple Profile Service
{
{ATT_BT_UUID_SIZE, primaryServiceUUID}, /* type */
GATT_PERMIT_READ, /* permissions */
0, /* handle */
(uint8_t *)&ble_uart_Service /* pValue */
},
#if 0
// Characteristic 1 Declaration
{
{ ATT_BT_UUID_SIZE, characterUUID },
GATT_PERMIT_READ,
0,
&ble_uart_RxCharProps
},
// Characteristic Value 1
{
{ ATT_UUID_SIZE, ble_uart_RxCharUUID },
GATT_PERMIT_WRITE,
0,
&ble_uart_RxCharValue[0]
},
#endif
// Characteristic 2 Declaration
{
{ATT_BT_UUID_SIZE, characterUUID},
GATT_PERMIT_READ,
0,
&ble_uart_TxCharProps},
// Characteristic Value 2
{
{ATT_BT_UUID_SIZE, ble_uart_TxCharUUID},
GATT_PERMIT_WRITE,
0,
(uint8_t *)&ble_uart_TxCharValue},
// Characteristic 2 User Description
{
{ATT_BT_UUID_SIZE, clientCharCfgUUID},
GATT_PERMIT_READ | GATT_PERMIT_WRITE,
0,
(uint8_t *)ble_uart_TxCCCD},
};
/*********************************************************************
* LOCAL FUNCTIONS
*/
static bStatus_t ble_uart_ReadAttrCB(uint16_t connHandle, gattAttribute_t *pAttr,
uint8_t *pValue, uint16_t *pLen, uint16_t offset, uint16_t maxLen, uint8_t method);
static bStatus_t ble_uart_WriteAttrCB(uint16_t connHandle, gattAttribute_t *pAttr,
uint8_t *pValue, uint16_t len, uint16_t offset, uint8_t method);
static void ble_uart_HandleConnStatusCB(uint16_t connHandle, uint8_t changeType);
/*********************************************************************
* PROFILE CALLBACKS
*/
// Simple Profile Service Callbacks
gattServiceCBs_t ble_uart_ProfileCBs = {
ble_uart_ReadAttrCB, // Read callback function pointer
ble_uart_WriteAttrCB, // Write callback function pointer
NULL // Authorization callback function pointer
};
/*********************************************************************
* PUBLIC FUNCTIONS
*/
/*********************************************************************
* @fn ble_uart_AddService
*
* @brief Initializes the Simple Profile service by registering
* GATT attributes with the GATT server.
*
* @param services - services to add. This is a bit map and can
* contain more than one service.
*
* @return Success or Failure
*/
bStatus_t ble_uart_add_service(ble_uart_ProfileChangeCB_t cb)
{
uint8_t status = SUCCESS;
GATTServApp_InitCharCfg(INVALID_CONNHANDLE, ble_uart_TxCCCD);
// Register with Link DB to receive link status change callback
linkDB_Register(ble_uart_HandleConnStatusCB);
// ble_uart_TxCCCD.connHandle = INVALID_CONNHANDLE;
// ble_uart_TxCCCD.value = 0;
// Register GATT attribute list and CBs with GATT Server App
status = GATTServApp_RegisterService(ble_uart_ProfileAttrTbl,
GATT_NUM_ATTRS(ble_uart_ProfileAttrTbl),
GATT_MAX_ENCRYPT_KEY_SIZE,
&ble_uart_ProfileCBs);
if(status != SUCCESS)
PRINT("Add ble uart service failed!\n");
ble_uart_AppCBs = cb;
return (status);
}
/*********************************************************************
* @fn ble_uart_ReadAttrCB
*
* @brief Read an attribute.
*
* @param connHandle - connection message was received on
* @param pAttr - pointer to attribute
* @param pValue - pointer to data to be read
* @param pLen - length of data to be read
* @param offset - offset of the first octet to be read
* @param maxLen - maximum length of data to be read
*
* @return Success or Failure
*/
static bStatus_t ble_uart_ReadAttrCB(uint16_t connHandle, gattAttribute_t *pAttr,
uint8_t *pValue, uint16_t *pLen, uint16_t offset, uint16_t maxLen, uint8_t method)
{
bStatus_t status = SUCCESS;
PRINT("ReadAttrCB\n");
// Make sure it's not a blob operation (no attributes in the profile are long)
if(pAttr->type.len == ATT_BT_UUID_SIZE)
{
// 16-bit UUID
uint16_t uuid = BUILD_UINT16(pAttr->type.uuid[0], pAttr->type.uuid[1]);
if(uuid == GATT_CLIENT_CHAR_CFG_UUID)
{
*pLen = 2;
tmos_memcpy(pValue, pAttr->pValue, 2);
}
}
else
{
if(!tmos_memcmp(pAttr->type.uuid, ble_uart_TxCharUUID, ATT_BT_UUID_SIZE))
{
*pLen = 1;
pValue[0] = '1';
}
// else if(!tmos_memcmp(pAttr->type.uuid, ble_uart_RxCharUUID, 16))
// {
// PRINT("read tx char\n");
// }
}
return (status);
}
/*********************************************************************
* @fn simpleProfile_WriteAttrCB
*
* @brief Validate attribute data prior to a write operation
*
* @param connHandle - connection message was received on
* @param pAttr - pointer to attribute
* @param pValue - pointer to data to be written
* @param len - length of data
* @param offset - offset of the first octet to be written
*
* @return Success or Failure
*/
static bStatus_t ble_uart_WriteAttrCB(uint16_t connHandle, gattAttribute_t *pAttr,
uint8_t *pValue, uint16_t len, uint16_t offset, uint8_t method)
{
bStatus_t status = SUCCESS;
//uint8_t notifyApp = 0xFF;
// If attribute permissions require authorization to write, return error
if(gattPermitAuthorWrite(pAttr->permissions))
{
// Insufficient authorization
return (ATT_ERR_INSUFFICIENT_AUTHOR);
}
if(pAttr->type.len == ATT_BT_UUID_SIZE)
{
// 16-bit UUID
uint16_t uuid = BUILD_UINT16(pAttr->type.uuid[0], pAttr->type.uuid[1]);
if(uuid == GATT_CLIENT_CHAR_CFG_UUID)
{
status = GATTServApp_ProcessCCCWriteReq(connHandle, pAttr, pValue, len,
offset, GATT_CLIENT_CFG_NOTIFY);
if(status == SUCCESS && ble_uart_AppCBs)
{
uint16_t charCfg = BUILD_UINT16(pValue[0], pValue[1]);
ble_uart_evt_t evt;
//PRINT("CCCD set: [%d]\n", charCfg);
evt.type = (charCfg == GATT_CFG_NO_OPERATION) ? BLE_UART_EVT_TX_NOTI_DISABLED : BLE_UART_EVT_TX_NOTI_ENABLED;
ble_uart_AppCBs(connHandle, &evt);
}
}
// 128-bit UUID
if(pAttr->handle == ble_uart_ProfileAttrTbl[RAWPASS_TX_VALUE_HANDLE].handle)
{
if(ble_uart_AppCBs)
{
ble_uart_evt_t evt;
evt.type = BLE_UART_EVT_BLE_DATA_RECIEVED;
evt.data.length = (uint16_t)len;
evt.data.p_data = pValue;
ble_uart_AppCBs(connHandle, &evt);
}
}
}
else
{
// 128-bit UUID
if(pAttr->handle == ble_uart_ProfileAttrTbl[RAWPASS_TX_VALUE_HANDLE].handle)
{
if(ble_uart_AppCBs)
{
ble_uart_evt_t evt;
evt.type = BLE_UART_EVT_BLE_DATA_RECIEVED;
evt.data.length = (uint16_t)len;
evt.data.p_data = pValue;
ble_uart_AppCBs(connHandle, &evt);
}
}
}
return (status);
}
/*********************************************************************
* @fn simpleProfile_HandleConnStatusCB
*
* @brief Simple Profile link status change handler function.
*
* @param connHandle - connection handle
* @param changeType - type of change
*
* @return none
*/
static void ble_uart_HandleConnStatusCB(uint16_t connHandle, uint8_t changeType)
{
// Make sure this is not loopback connection
if(connHandle != LOOPBACK_CONNHANDLE)
{
// Reset Client Char Config if connection has dropped
if((changeType == LINKDB_STATUS_UPDATE_REMOVED) ||
((changeType == LINKDB_STATUS_UPDATE_STATEFLAGS) &&
(!linkDB_Up(connHandle))))
{
//ble_uart_TxCCCD[0].value = 0;
GATTServApp_InitCharCfg(connHandle, ble_uart_TxCCCD);
//PRINT("clear client configuration\n");
}
}
}
uint8_t ble_uart_notify_is_ready(uint16_t connHandle)
{
return (GATT_CLIENT_CFG_NOTIFY == GATTServApp_ReadCharCfg(connHandle, ble_uart_TxCCCD));
}
/*********************************************************************
* @fn BloodPressure_IMeasNotify
*
* @brief Send a notification containing a bloodPressure
* measurement.
*
* @param connHandle - connection handle
* @param pNoti - pointer to notification structure
*
* @return Success or Failure
*/
bStatus_t ble_uart_notify(uint16_t connHandle, attHandleValueNoti_t *pNoti, uint8_t taskId)
{
//uint16_t value = ble_uart_TxCCCD[0].value;
uint16_t value = GATTServApp_ReadCharCfg(connHandle, ble_uart_TxCCCD);
// If notifications enabled
if(value & GATT_CLIENT_CFG_NOTIFY)
{
// Set the handle
pNoti->handle = ble_uart_ProfileAttrTbl[RAWPASS_TX_VALUE_HANDLE].handle;
// Send the Indication
return GATT_Notification(connHandle, pNoti, FALSE);
}
return bleIncorrectMode;
}
/*********************************************************************
*********************************************************************/
@@ -0,0 +1,381 @@
/********************************** (C) COPYRIGHT *******************************
* File Name : ble_uart_service_same_char.c
* Author : WCH
* Version : V1.1
* Date : 2022/01/19
* 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 "gattprofile.h"
#include "stdint.h"
#include "ble_uart_service.h"
/*********************************************************************
* MACROS
*/
/*********************************************************************
* CONSTANTS
*/
#define SERVAPP_NUM_ATTR_SUPPORTED 7
#define RAWPASS_TX_VALUE_HANDLE 2
//#define RAWPASS_RX_VALUE_HANDLE 2
/*********************************************************************
* TYPEDEFS
*/
/*********************************************************************
* GLOBAL VARIABLES
*/
////ble_uart GATT Profile Service UUID
//const uint8_t ble_uart_ServiceUUID[ATT_UUID_SIZE] =
//{0x55, 0xe4,0x05,0xd2,0xaf,0x9f,0xa9,0x8f,0xe5,0x4a,0x7d,0xfe,0x43,0x53,0x53,0x49};
//// Characteristic rx uuid
//const uint8_t ble_uart_RxCharUUID[ATT_UUID_SIZE] =
//{0xb3,0x9b,0x72,0x34,0xbe,0xec, 0xd4,0xa8,0xf4,0x43,0x41,0x88,0x43,0x53,0x53,0x49};
//// Characteristic tx uuid
//const uint8_t ble_uart_TxCharUUID[ATT_UUID_SIZE] =
//{0x16,0x96,0x24,0x47,0xc6,0x23, 0x61,0xba,0xd9,0x4b,0x4d,0x1e,0x43,0x53,0x53,0x49};
// ble_uart GATT Profile Service UUID
const uint8_t ble_uart_ServiceUUID[ATT_UUID_SIZE] =
{0x9E, 0xCA, 0xDC, 0x24, 0x0E, 0xE5, 0xA9, 0xE0, 0x93, 0xF3, 0xA3, 0xB5, 0x01, 0x00, 0x40, 0x6E};
// Characteristic rx uuid
//const uint8_t ble_uart_RxCharUUID[ATT_UUID_SIZE] =
//{0x9E, 0xCA, 0xDC, 0x24, 0x0E, 0xE5, 0xA9, 0xE0, 0x93, 0xF3, 0xA3, 0xB5, 0x02, 0x00, 0x40, 0x6E};
// Characteristic tx uuid
const uint8_t ble_uart_TxCharUUID[ATT_UUID_SIZE] =
{0x9E, 0xCA, 0xDC, 0x24, 0x0E, 0xE5, 0xA9, 0xE0, 0x93, 0xF3, 0xA3, 0xB5, 0x03, 0x00, 0x40, 0x6E};
/*********************************************************************
* EXTERNAL VARIABLES
*/
/*********************************************************************
* EXTERNAL FUNCTIONS
*/
/*********************************************************************
* LOCAL VARIABLES
*/
static ble_uart_ProfileChangeCB_t ble_uart_AppCBs = NULL;
/*********************************************************************
* Profile Attributes - variables
*/
// Profile Service attribute
static const gattAttrType_t ble_uart_Service = {ATT_UUID_SIZE, ble_uart_ServiceUUID};
// Profile Characteristic 1 Properties
//static uint8_t ble_uart_RxCharProps = GATT_PROP_WRITE_NO_RSP| GATT_PROP_WRITE;
//static uint8_t ble_uart_RxCharProps = GATT_PROP_WRITE_NO_RSP;
// Characteristic 1 Value
static uint8_t ble_uart_RxCharValue[BLE_UART_RX_BUFF_SIZE];
//static uint8_t ble_uart_RxCharValue[1];
// Profile Characteristic 2 Properties
//static uint8_t ble_uart_TxCharProps = GATT_PROP_NOTIFY| GATT_PROP_INDICATE;
static uint8_t ble_uart_TxCharProps = GATT_PROP_WRITE_NO_RSP | GATT_PROP_NOTIFY;
// Characteristic 2 Value
static uint8_t ble_uart_TxCharValue = 0;
// Simple Profile Characteristic 2 User Description
static gattCharCfg_t ble_uart_TxCCCD[4];
/*********************************************************************
* Profile Attributes - Table
*/
static gattAttribute_t ble_uart_ProfileAttrTbl[] = {
// Simple Profile Service
{
{ATT_BT_UUID_SIZE, primaryServiceUUID}, /* type */
GATT_PERMIT_READ, /* permissions */
0, /* handle */
(uint8_t *)&ble_uart_Service /* pValue */
},
#if 0
// Characteristic 1 Declaration
{
{ ATT_BT_UUID_SIZE, characterUUID },
GATT_PERMIT_READ,
0,
&ble_uart_RxCharProps
},
// Characteristic Value 1
{
{ ATT_UUID_SIZE, ble_uart_RxCharUUID },
GATT_PERMIT_WRITE,
0,
&ble_uart_RxCharValue[0]
},
#endif
// Characteristic 2 Declaration
{
{ATT_BT_UUID_SIZE, characterUUID},
GATT_PERMIT_READ,
0,
&ble_uart_TxCharProps},
// Characteristic Value 2
{
{ATT_UUID_SIZE, ble_uart_TxCharUUID},
GATT_PERMIT_WRITE,
0,
(uint8_t *)&ble_uart_TxCharValue},
// Characteristic 2 User Description
{
{ATT_BT_UUID_SIZE, clientCharCfgUUID},
GATT_PERMIT_READ | GATT_PERMIT_WRITE,
0,
(uint8_t *)ble_uart_TxCCCD},
};
/*********************************************************************
* LOCAL FUNCTIONS
*/
static bStatus_t ble_uart_ReadAttrCB(uint16_t connHandle, gattAttribute_t *pAttr,
uint8_t *pValue, uint16_t *pLen, uint16_t offset, uint16_t maxLen, uint8_t method);
static bStatus_t ble_uart_WriteAttrCB(uint16_t connHandle, gattAttribute_t *pAttr,
uint8_t *pValue, uint16_t len, uint16_t offset, uint8_t method);
static void ble_uart_HandleConnStatusCB(uint16_t connHandle, uint8_t changeType);
/*********************************************************************
* PROFILE CALLBACKS
*/
// Simple Profile Service Callbacks
gattServiceCBs_t ble_uart_ProfileCBs = {
ble_uart_ReadAttrCB, // Read callback function pointer
ble_uart_WriteAttrCB, // Write callback function pointer
NULL // Authorization callback function pointer
};
/*********************************************************************
* PUBLIC FUNCTIONS
*/
/*********************************************************************
* @fn ble_uart_AddService
*
* @brief Initializes the Simple Profile service by registering
* GATT attributes with the GATT server.
*
* @param services - services to add. This is a bit map and can
* contain more than one service.
*
* @return Success or Failure
*/
bStatus_t ble_uart_add_service(ble_uart_ProfileChangeCB_t cb)
{
uint8_t status = SUCCESS;
GATTServApp_InitCharCfg(INVALID_CONNHANDLE, ble_uart_TxCCCD);
// Register with Link DB to receive link status change callback
linkDB_Register(ble_uart_HandleConnStatusCB);
// ble_uart_TxCCCD.connHandle = INVALID_CONNHANDLE;
// ble_uart_TxCCCD.value = 0;
// Register GATT attribute list and CBs with GATT Server App
status = GATTServApp_RegisterService(ble_uart_ProfileAttrTbl,
GATT_NUM_ATTRS(ble_uart_ProfileAttrTbl),
GATT_MAX_ENCRYPT_KEY_SIZE,
&ble_uart_ProfileCBs);
if(status != SUCCESS)
PRINT("Add ble uart service failed!\n");
ble_uart_AppCBs = cb;
return (status);
}
/*********************************************************************
* @fn ble_uart_ReadAttrCB
*
* @brief Read an attribute.
*
* @param connHandle - connection message was received on
* @param pAttr - pointer to attribute
* @param pValue - pointer to data to be read
* @param pLen - length of data to be read
* @param offset - offset of the first octet to be read
* @param maxLen - maximum length of data to be read
*
* @return Success or Failure
*/
static bStatus_t ble_uart_ReadAttrCB(uint16_t connHandle, gattAttribute_t *pAttr,
uint8_t *pValue, uint16_t *pLen, uint16_t offset, uint16_t maxLen, uint8_t method)
{
bStatus_t status = SUCCESS;
PRINT("ReadAttrCB\n");
// Make sure it's not a blob operation (no attributes in the profile are long)
if(pAttr->type.len == ATT_BT_UUID_SIZE)
{
// 16-bit UUID
uint16_t uuid = BUILD_UINT16(pAttr->type.uuid[0], pAttr->type.uuid[1]);
if(uuid == GATT_CLIENT_CHAR_CFG_UUID)
{
*pLen = 2;
tmos_memcpy(pValue, pAttr->pValue, 2);
}
}
else
{
if(!tmos_memcmp(pAttr->type.uuid, ble_uart_TxCharUUID, 16))
{
*pLen = 1;
pValue[0] = '1';
}
// else if(!tmos_memcmp(pAttr->type.uuid, ble_uart_RxCharUUID, 16))
// {
// PRINT("read tx char\n");
// }
}
return (status);
}
/*********************************************************************
* @fn simpleProfile_WriteAttrCB
*
* @brief Validate attribute data prior to a write operation
*
* @param connHandle - connection message was received on
* @param pAttr - pointer to attribute
* @param pValue - pointer to data to be written
* @param len - length of data
* @param offset - offset of the first octet to be written
*
* @return Success or Failure
*/
static bStatus_t ble_uart_WriteAttrCB(uint16_t connHandle, gattAttribute_t *pAttr,
uint8_t *pValue, uint16_t len, uint16_t offset, uint8_t method)
{
bStatus_t status = SUCCESS;
//uint8_t notifyApp = 0xFF;
// If attribute permissions require authorization to write, return error
if(gattPermitAuthorWrite(pAttr->permissions))
{
// Insufficient authorization
return (ATT_ERR_INSUFFICIENT_AUTHOR);
}
if(pAttr->type.len == ATT_BT_UUID_SIZE)
{
// 16-bit UUID
uint16_t uuid = BUILD_UINT16(pAttr->type.uuid[0], pAttr->type.uuid[1]);
if(uuid == GATT_CLIENT_CHAR_CFG_UUID)
{
status = GATTServApp_ProcessCCCWriteReq(connHandle, pAttr, pValue, len,
offset, GATT_CLIENT_CFG_NOTIFY);
if(status == SUCCESS && ble_uart_AppCBs)
{
uint16_t charCfg = BUILD_UINT16(pValue[0], pValue[1]);
ble_uart_evt_t evt;
//PRINT("CCCD set: [%d]\n", charCfg);
evt.type = (charCfg == GATT_CFG_NO_OPERATION) ? BLE_UART_EVT_TX_NOTI_DISABLED : BLE_UART_EVT_TX_NOTI_ENABLED;
ble_uart_AppCBs(connHandle, &evt);
}
}
}
else
{
// 128-bit UUID
if(pAttr->handle == ble_uart_ProfileAttrTbl[RAWPASS_TX_VALUE_HANDLE].handle)
{
if(ble_uart_AppCBs)
{
ble_uart_evt_t evt;
evt.type = BLE_UART_EVT_BLE_DATA_RECIEVED;
evt.data.length = (uint16_t)len;
evt.data.p_data = pValue;
ble_uart_AppCBs(connHandle, &evt);
}
}
}
return (status);
}
/*********************************************************************
* @fn simpleProfile_HandleConnStatusCB
*
* @brief Simple Profile link status change handler function.
*
* @param connHandle - connection handle
* @param changeType - type of change
*
* @return none
*/
static void ble_uart_HandleConnStatusCB(uint16_t connHandle, uint8_t changeType)
{
// Make sure this is not loopback connection
if(connHandle != LOOPBACK_CONNHANDLE)
{
// Reset Client Char Config if connection has dropped
if((changeType == LINKDB_STATUS_UPDATE_REMOVED) ||
((changeType == LINKDB_STATUS_UPDATE_STATEFLAGS) &&
(!linkDB_Up(connHandle))))
{
//ble_uart_TxCCCD[0].value = 0;
GATTServApp_InitCharCfg(connHandle, ble_uart_TxCCCD);
//PRINT("clear client configuration\n");
}
}
}
uint8_t ble_uart_notify_is_ready(uint16_t connHandle)
{
return (GATT_CLIENT_CFG_NOTIFY == GATTServApp_ReadCharCfg(connHandle, ble_uart_TxCCCD));
}
/*********************************************************************
* @fn BloodPressure_IMeasNotify
*
* @brief Send a notification containing a bloodPressure
* measurement.
*
* @param connHandle - connection handle
* @param pNoti - pointer to notification structure
*
* @return Success or Failure
*/
bStatus_t ble_uart_notify(uint16_t connHandle, attHandleValueNoti_t *pNoti, uint8_t taskId)
{
//uint16_t value = ble_uart_TxCCCD[0].value;
uint16_t value = GATTServApp_ReadCharCfg(connHandle, ble_uart_TxCCCD);
// If notifications enabled
if(value & GATT_CLIENT_CFG_NOTIFY)
{
// Set the handle
pNoti->handle = ble_uart_ProfileAttrTbl[RAWPASS_TX_VALUE_HANDLE].handle;
// Send the Indication
return GATT_Notification(connHandle, pNoti, FALSE);
}
return bleIncorrectMode;
}
/*********************************************************************
*********************************************************************/
+74
View File
@@ -0,0 +1,74 @@
/********************************** (C) COPYRIGHT *******************************
* File Name : ch32v20x_it.c
* Author : WCH
* Version : V1.0.0
* Date : 2022/06/16
* Description : Main Interrupt Service Routines.
*********************************************************************************
* 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 "ch32v20x_it.h"
#include "CONFIG.h"
/*********************************************************************
* LOCAL FUNCTIONS
*/
void NMI_Handler(void) __attribute__((interrupt("WCH-Interrupt-fast")));
void HardFault_Handler(void) __attribute__((interrupt("WCH-Interrupt-fast")));
void BB_IRQHandler(void) __attribute__((interrupt("WCH-Interrupt-fast")));
void LLE_IRQHandler(void) __attribute__((interrupt("WCH-Interrupt-fast")));
/*********************************************************************
* @fn NMI_Handler
*
* @brief This function handles NMI exception.
*
* @return None
*/
void NMI_Handler(void)
{
}
/*********************************************************************
* @fn HardFault_Handler
*
* @brief This function handles Hard Fault exception.
*
* @return None
*/
void HardFault_Handler(void)
{
while(1)
{
}
}
/*********************************************************************
* @fn BB_IRQHandler
*
* @brief BB Interrupt for BLE.
*
* @return None
*/
void BB_IRQHandler(void)
{
BB_IRQLibHandler();
}
/*********************************************************************
* @fn LLE_IRQHandler
*
* @brief LLE Interrupt for BLE.
*
* @return None
*/
void LLE_IRQHandler(void)
{
LLE_IRQLibHandler();
}
@@ -0,0 +1,37 @@
/********************************** (C) COPYRIGHT *******************************
* File Name : ch32v20x_conf.h
* Author : WCH
* Version : V1.0.0
* Date : 2022/06/16
* Description : Library configuration file.
*********************************************************************************
* 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.
*******************************************************************************/
#ifndef __CH32V20x_CONF_H
#define __CH32V20x_CONF_H
#include "ch32v20x_adc.h"
#include "ch32v20x_bkp.h"
#include "ch32v20x_can.h"
#include "ch32v20x_crc.h"
#include "ch32v20x_dbgmcu.h"
#include "ch32v20x_dma.h"
#include "ch32v20x_exti.h"
#include "ch32v20x_flash.h"
#include "ch32v20x_gpio.h"
#include "ch32v20x_i2c.h"
#include "ch32v20x_iwdg.h"
#include "ch32v20x_pwr.h"
#include "ch32v20x_rcc.h"
#include "ch32v20x_rtc.h"
#include "ch32v20x_spi.h"
#include "ch32v20x_tim.h"
#include "ch32v20x_usart.h"
#include "ch32v20x_wwdg.h"
#include "ch32v20x_it.h"
#include "ch32v20x_misc.h"
#endif /* __CH32V20x_CONF_H */
@@ -0,0 +1,18 @@
/********************************** (C) COPYRIGHT *******************************
* File Name : ch32v20x_it.h
* Author : WCH
* Version : V1.0.0
* Date : 2022/06/16
* Description : This file contains the headers of the interrupt handlers.
*********************************************************************************
* 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.
*******************************************************************************/
#ifndef __CH32V20x_IT_H
#define __CH32V20x_IT_H
#include "debug.h"
#endif /* __CH32V20x_IT_H */
@@ -0,0 +1,67 @@
/********************************** (C) COPYRIGHT *******************************
* File Name : peripheral.h
* Author : WCH
* Version : V1.0
* Date : 2018/12/11
* 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.
*******************************************************************************/
#ifndef PERIPHERAL_H
#define PERIPHERAL_H
#ifdef __cplusplus
extern "C" {
#endif
/*********************************************************************
* INCLUDES
*/
/*********************************************************************
* CONSTANTS
*/
// Peripheral Task Events
#define SBP_START_DEVICE_EVT 0x0001
#define SBP_READ_RSSI_EVT 0x0004
#define SBP_PARAM_UPDATE_EVT 0x0008
#define UART_TO_BLE_SEND_EVT 0x0010
/*********************************************************************
* MACROS
*/
typedef struct
{
uint16_t connHandle; // Connection handle of current connection
uint16_t connInterval;
uint16_t connSlaveLatency;
uint16_t connTimeout;
} peripheralConnItem_t;
/*********************************************************************
* FUNCTIONS
*/
/*
* Task Initialization for the BLE Application
*/
extern void Peripheral_Init(void);
/*
* Task Event Processor for the BLE Application
*/
extern uint16_t Peripheral_ProcessEvent(uint8_t task_id, uint16_t events);
/*********************************************************************
*********************************************************************/
#ifdef __cplusplus
}
#endif
#endif
@@ -0,0 +1,31 @@
/********************************** (C) COPYRIGHT *******************************
* File Name : system_ch32v20x.h
* Author : WCH
* Version : V1.0.0
* Date : 2022/06/16
* Description : CH32V20x Device Peripheral Access Layer System Header File.
*********************************************************************************
* 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.
*******************************************************************************/
#ifndef __SYSTEM_ch32v20x_H
#define __SYSTEM_ch32v20x_H
#ifdef __cplusplus
extern "C" {
#endif
extern uint32_t SystemCoreClock; /* System Clock Frequency (Core Clock) */
/* System_Exported_Functions */
extern void SystemInit(void);
extern void SystemCoreClockUpdate(void);
#ifdef __cplusplus
}
#endif
#endif /*__CH32V20x_SYSTEM_H */
+794
View File
@@ -0,0 +1,794 @@
/********************************** (C) COPYRIGHT *******************************
* File Name : peripheral.C
* Author : zhangxiyi @WCH
* Version : v0.1
* Date : 2020/11/26
* 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 "ble_uart_service.h"
#include "app_drv_fifo.h"
uint8_t Peripheral_TaskID = INVALID_TASK_ID; // Task ID for internal task/event processing
//
static uint8_t to_test_buffer[BLE_BUFF_MAX_LEN - 4 - 3];
//The buffer length should be a power of 2
#define APP_UART_TX_BUFFER_LENGTH 512U
#define APP_UART_RX_BUFFER_LENGTH 2048U
//The tx buffer and rx buffer for app_drv_fifo
//length should be a power of 2
static uint8_t app_uart_tx_buffer[APP_UART_TX_BUFFER_LENGTH] = {0};
static uint8_t app_uart_rx_buffer[APP_UART_RX_BUFFER_LENGTH] = {0};
static app_drv_fifo_t app_uart_tx_fifo;
static app_drv_fifo_t app_uart_rx_fifo;
//interupt uart rx flag ,clear at main loop
bool uart_rx_flag = false;
//for interrupt rx blcak hole ,when uart rx fifo full
uint8_t for_uart_rx_black_hole = 0;
//fifo length less that MTU-3, retry times
uint32_t uart_to_ble_send_evt_cnt = 0;
void app_uart_process(void)
{
uint8_t data;
__disable_irq();
if(uart_rx_flag)
{
tmos_start_task(Peripheral_TaskID, UART_TO_BLE_SEND_EVT, 2);
uart_rx_flag = false;
}
__enable_irq();
while(app_drv_fifo_length(&app_uart_tx_fifo))
{
app_drv_fifo_read_to_same_addr(&app_uart_tx_fifo, (uint8_t *)&data, 1);
USART_SendData(USART3, data);
while(USART_GetFlagStatus(USART3, USART_FLAG_TXE) == RESET) /* waiting for sending finish */
{
}
}
}
void app_uart_init()
{
//tx fifo and tx fifo
//The buffer length should be a power of 2
app_drv_fifo_init(&app_uart_tx_fifo, app_uart_tx_buffer, APP_UART_TX_BUFFER_LENGTH);
app_drv_fifo_init(&app_uart_rx_fifo, app_uart_rx_buffer, APP_UART_RX_BUFFER_LENGTH);
GPIO_InitTypeDef GPIO_InitStructure = {0};
USART_InitTypeDef USART_InitStructure = {0};
NVIC_InitTypeDef NVIC_InitStructure = {0};
//uart3 init
RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART3, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
/* USART3 TX-->B.10 RX-->B.11 */
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_Init(GPIOB, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_Init(GPIOB, &GPIO_InitStructure);
USART_InitStructure.USART_BaudRate = 115200;
USART_InitStructure.USART_WordLength = USART_WordLength_8b;
USART_InitStructure.USART_StopBits = USART_StopBits_1;
USART_InitStructure.USART_Parity = USART_Parity_No;
USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
USART_InitStructure.USART_Mode = USART_Mode_Tx | USART_Mode_Rx;
USART_Init(USART3, &USART_InitStructure);
USART_ITConfig(USART3, USART_IT_RXNE, ENABLE);
NVIC_InitStructure.NVIC_IRQChannel = USART3_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
USART_Cmd(USART3, ENABLE);
}
void app_uart_tx_data(uint8_t *data, uint16_t length)
{
uint16_t write_length = length;
app_drv_fifo_write(&app_uart_tx_fifo, data, &write_length);
}
//
//Not every uart reception will end with a UART_II_RECV_TOUT
//UART_II_RECV_TOUT can only be triggered when R8_UARTx_RFC is not 0
//Here we cannot rely UART_II_RECV_TOUT as the end of a uart reception
__attribute__((interrupt("WCH-Interrupt-fast")))
void USART3_IRQHandler(void)
{
uint16_t error;
uint8_t data;
if(USART_GetITStatus(USART3, USART_IT_RXNE) != RESET)
{
data = USART_ReceiveData(USART3);
error = app_drv_fifo_write_from_same_addr(&app_uart_rx_fifo, (uint8_t *)&data, 1);
if(error != APP_DRV_FIFO_RESULT_SUCCESS)
{
PRINT("APP_DRV_FIFO_RESULT_NOT_MEM\r\n");
}
uart_rx_flag = true;
}
}
//ble uart service callback handler
void on_bleuartServiceEvt(uint16_t connection_handle, ble_uart_evt_t *p_evt)
{
switch(p_evt->type)
{
case BLE_UART_EVT_TX_NOTI_DISABLED:
PRINT("%02x:bleuart_EVT_TX_NOTI_DISABLED\r\n", connection_handle);
break;
case BLE_UART_EVT_TX_NOTI_ENABLED:
PRINT("%02x:bleuart_EVT_TX_NOTI_ENABLED\r\n", connection_handle);
break;
case BLE_UART_EVT_BLE_DATA_RECIEVED:
PRINT("BLE RX DATA len:%d\r\n", p_evt->data.length);
//for notify back test
//to ble
uint16_t to_write_length = p_evt->data.length;
app_drv_fifo_write(&app_uart_rx_fifo, (uint8_t *)p_evt->data.p_data, &to_write_length);
tmos_start_task(Peripheral_TaskID, UART_TO_BLE_SEND_EVT, 2);
//end of nofify back test
//ble to uart
app_uart_tx_data((uint8_t *)p_evt->data.p_data, p_evt->data.length);
break;
default:
break;
}
}
/*********************************************************************
* MACROS
*/
/*********************************************************************
* CONSTANTS
*/
// How often to perform periodic event
#define SBP_PERIODIC_EVT_PERIOD 1600
// How often to perform read rssi event
#define SBP_READ_RSSI_EVT_PERIOD 3200
// Parameter update delay
#define SBP_PARAM_UPDATE_DELAY 6400
// What is the advertising interval when device is discoverable (units of 625us, 80=50ms)
#define DEFAULT_ADVERTISING_INTERVAL 160
// 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, 10=12.5ms)
#define DEFAULT_DESIRED_MIN_CONN_INTERVAL 8
// Maximum connection interval (units of 1.25ms, 100=125ms)
#define DEFAULT_DESIRED_MAX_CONN_INTERVAL 20
// 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
// Company Identifier: WCH
#define WCH_COMPANY_ID 0x07D7
/*********************************************************************
* TYPEDEFS
*/
/*********************************************************************
* GLOBAL VARIABLES
*/
/*********************************************************************
* EXTERNAL VARIABLES
*/
/*********************************************************************
* EXTERNAL FUNCTIONS
*/
/*********************************************************************
* LOCAL VARIABLES
*/
//for send to ble
typedef enum
{
SEND_TO_BLE_TO_SEND = 1,
SEND_TO_BLE_ALLOC_FAILED,
SEND_TO_BLE_SEND_FAILED,
} send_to_ble_state_t;
send_to_ble_state_t send_to_ble_state = SEND_TO_BLE_TO_SEND;
blePaControlConfig_t pa_lna_ctl;
//static uint8_t Peripheral_TaskID = INVALID_TASK_ID; // Task ID for internal task/event processing
// GAP - SCAN RSP data (max size = 31 bytes)
static uint8_t scanRspData[] = {
// complete name
13, // length of this data
GAP_ADTYPE_LOCAL_NAME_COMPLETE,
'w', 'c', 'h', '_', 'b', 'l', 'e', '_', 'u', 'a', 'r', 't',
// 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 advertisting)
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] = "ch32v208_ble_uart";
// Connection item list
static peripheralConnItem_t peripheralConnList;
/*********************************************************************
* LOCAL FUNCTIONS
*/
static void Peripheral_ProcessTMOSMsg(tmos_event_hdr_t *pMsg);
static void peripheralStateNotificationCB(gapRole_States_t newState, gapRoleEvent_t *pEvent);
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);
/*********************************************************************
* 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)
};
/*********************************************************************
* 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 = 6;
uint16_t desired_max_interval = 1000;
// 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);
}
// Set the GAP Characteristics
GGS_SetParameter(GGS_DEVICE_NAME_ATT, GAP_DEVICE_NAME_LEN, attDeviceName);
// Set advertising interval
{
uint16_t advInt = DEFAULT_ADVERTISING_INTERVAL;
GAP_SetParamValue(TGAP_DISC_ADV_INT_MIN, advInt);
GAP_SetParamValue(TGAP_DISC_ADV_INT_MAX, advInt);
}
// 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
ble_uart_add_service(on_bleuartServiceEvt);
// Init Connection Item
peripheralInitConnItem(&peripheralConnList);
// Register receive scan request callback
GAPRole_BroadcasterSetCB(&Broadcaster_BroadcasterCBs);
// Setup a delayed profile startup
tmos_set_event(Peripheral_TaskID, SBP_START_DEVICE_EVT);
}
/*********************************************************************
* @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;
}
uint32_t get_fattime(void)
{
return 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)
{
static attHandleValueNoti_t noti;
// 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_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);
// GAPRole_PeripheralConnParamUpdateReq( peripheralConnList.connHandle,
// 10,
// 20,
// 0,
// 400,
// Peripheral_TaskID);
return (events ^ SBP_PARAM_UPDATE_EVT);
}
if(events & UART_TO_BLE_SEND_EVT)
{
static uint16_t read_length = 0;
;
uint8_t result = 0xff;
switch(send_to_ble_state)
{
case SEND_TO_BLE_TO_SEND:
//notify is not enabled
if(!ble_uart_notify_is_ready(peripheralConnList.connHandle))
{
if(peripheralConnList.connHandle == GAP_CONNHANDLE_INIT)
{
//connection lost, flush rx fifo here
app_drv_fifo_flush(&app_uart_rx_fifo);
}
break;
}
read_length = ATT_GetMTU(peripheralConnList.connHandle) - 3;
if(app_drv_fifo_length(&app_uart_rx_fifo) >= read_length)
{
PRINT("FIFO_LEN:%d\r\n", app_drv_fifo_length(&app_uart_rx_fifo));
result = app_drv_fifo_read(&app_uart_rx_fifo, to_test_buffer, &read_length);
uart_to_ble_send_evt_cnt = 0;
}
else
{
if(uart_to_ble_send_evt_cnt > 10)
{
result = app_drv_fifo_read(&app_uart_rx_fifo, to_test_buffer, &read_length);
uart_to_ble_send_evt_cnt = 0;
}
else
{
tmos_start_task(Peripheral_TaskID, UART_TO_BLE_SEND_EVT, 4);
uart_to_ble_send_evt_cnt++;
PRINT("NO TIME OUT\r\n");
}
}
if(APP_DRV_FIFO_RESULT_SUCCESS == result)
{
noti.len = read_length;
noti.pValue = GATT_bm_alloc(peripheralConnList.connHandle, ATT_HANDLE_VALUE_NOTI, noti.len, NULL, 0);
if(noti.pValue != NULL)
{
tmos_memcpy(noti.pValue, to_test_buffer, noti.len);
result = ble_uart_notify(peripheralConnList.connHandle, &noti, 0);
if(result != SUCCESS)
{
PRINT("R1:%02x\r\n", result);
send_to_ble_state = SEND_TO_BLE_SEND_FAILED;
GATT_bm_free((gattMsg_t *)&noti, ATT_HANDLE_VALUE_NOTI);
tmos_start_task(Peripheral_TaskID, UART_TO_BLE_SEND_EVT, 2);
}
else
{
send_to_ble_state = SEND_TO_BLE_TO_SEND;
//app_fifo_write(&app_uart_tx_fifo,to_test_buffer,&read_length);
//app_drv_fifo_write(&app_uart_tx_fifo,to_test_buffer,&read_length);
read_length = 0;
tmos_start_task(Peripheral_TaskID, UART_TO_BLE_SEND_EVT, 2);
}
}
else
{
send_to_ble_state = SEND_TO_BLE_ALLOC_FAILED;
tmos_start_task(Peripheral_TaskID, UART_TO_BLE_SEND_EVT, 2);
}
}
else
{
//send_to_ble_state = SEND_TO_BLE_FIFO_EMPTY;
}
break;
case SEND_TO_BLE_ALLOC_FAILED:
case SEND_TO_BLE_SEND_FAILED:
noti.len = read_length;
noti.pValue = GATT_bm_alloc(peripheralConnList.connHandle, ATT_HANDLE_VALUE_NOTI, noti.len, NULL, 0);
if(noti.pValue != NULL)
{
tmos_memcpy(noti.pValue, to_test_buffer, noti.len);
result = ble_uart_notify(peripheralConnList.connHandle, &noti, 0);
if(result != SUCCESS)
{
PRINT("R2:%02x\r\n", result);
send_to_ble_state = SEND_TO_BLE_SEND_FAILED;
GATT_bm_free((gattMsg_t *)&noti, ATT_HANDLE_VALUE_NOTI);
tmos_start_task(Peripheral_TaskID, UART_TO_BLE_SEND_EVT, 2);
}
else
{
send_to_ble_state = SEND_TO_BLE_TO_SEND;
//app_drv_fifo_write(&app_uart_tx_fifo,to_test_buffer,&read_length);
read_length = 0;
tmos_start_task(Peripheral_TaskID, UART_TO_BLE_SEND_EVT, 2);
}
}
else
{
send_to_ble_state = SEND_TO_BLE_ALLOC_FAILED;
tmos_start_task(Peripheral_TaskID, UART_TO_BLE_SEND_EVT, 2);
}
break;
default:
break;
}
return (events ^ UART_TO_BLE_SEND_EVT);
}
// Discard unknown events
return 0;
}
/*********************************************************************
* @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)
{
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);
PRINT("Connection max...\n");
}
else
{
peripheralConnList.connHandle = event->connectionHandle;
peripheralConnList.connInterval = event->connInterval;
peripheralConnList.connSlaveLatency = event->connLatency;
peripheralConnList.connTimeout = event->connTimeout;
// Set timer for param update event
tmos_start_task(Peripheral_TaskID, SBP_PARAM_UPDATE_EVT, SBP_PARAM_UPDATE_DELAY);
PRINT("Conn %x - Int %x \n", event->connectionHandle, event->connInterval);
}
}
/*********************************************************************
* @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;
// Restart advertising
{
uint8_t advertising_enable = TRUE;
GAPRole_SetParameter(GAPROLE_ADVERT_ENABLED, sizeof(uint8_t), &advertising_enable);
}
}
else
{
PRINT("ERR..\n");
}
}
/*********************************************************************
* @fn peripheralRssiCB
*
* @brief RSSI callback.
*
* @param connHandle - connection handle
* @param rssi - RSSI
*
* @return none
*/
static void peripheralRssiCB(uint16_t connHandle, int8_t rssi)
{
PRINT("RSSI -%d dB Conn %x \n", -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;
PRINT("Update %x - Int %x \n", connHandle, connInterval);
}
else
{
PRINT("peripheralParamUpdateCB err..\n");
}
}
/*********************************************************************
* @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:
PRINT("Initialized..\n");
break;
case GAPROLE_ADVERTISING:
if(pEvent->gap.opcode == GAP_LINK_TERMINATED_EVENT)
{
Peripheral_LinkTerminated(pEvent);
}
PRINT("Advertising..\n");
break;
case GAPROLE_CONNECTED:
if(pEvent->gap.opcode == GAP_LINK_ESTABLISHED_EVENT)
{
Peripheral_LinkEstablished(pEvent);
PRINT("Connected..\n");
}
break;
case GAPROLE_CONNECTED_ADV:
PRINT("Connected Advertising..\n");
break;
case GAPROLE_WAITING:
if(pEvent->gap.opcode == GAP_END_DISCOVERABLE_DONE_EVENT)
{
PRINT("Waiting for advertising..\n");
}
else if(pEvent->gap.opcode == GAP_LINK_TERMINATED_EVENT)
{
Peripheral_LinkTerminated(pEvent);
PRINT("Disconnected.. Reason:%x\n", pEvent->linkTerminate.reason);
}
else if(pEvent->gap.opcode == GAP_LINK_ESTABLISHED_EVENT)
{
if(pEvent->gap.hdr.status != SUCCESS)
{
PRINT("Waiting for advertising..\n");
}
else
{
PRINT("Error..\n");
}
}
else
{
PRINT("Error..%x\n", pEvent->gap.opcode);
}
break;
case GAPROLE_ERROR:
PRINT("Error..\n");
break;
default:
break;
}
}
/*********************************************************************
*********************************************************************/
@@ -0,0 +1,72 @@
/********************************** (C) COPYRIGHT *******************************
* File Name : main.c
* Author : WCH
* Version : V1.1
* Date : 2020/08/06
* Description : Peripheral slave application main function and task system initialization
*********************************************************************************
* 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.
*******************************************************************************/
/******************************************************************************/
/* Header file contains */
#include "CONFIG.h"
#include "HAL.h"
#include "gattprofile.h"
#include "peripheral.h"
/*********************************************************************
* GLOBAL TYPEDEFS
*/
__attribute__((aligned(4))) u32 MEM_BUF[BLE_MEMHEAP_SIZE / 4];
#if(defined(BLE_MAC)) && (BLE_MAC == TRUE)
uint8_t const MacAddr[6] = {0x84, 0xC2, 0xE4, 0x03, 0x02, 0x02};
#endif
extern void app_uart_process(void);
extern void app_uart_init(void);
/*********************************************************************
* @fn Main_Circulation
*
* @brief Main loop
*
* @return none
*/
__attribute__((section(".highcode")))
__attribute__((noinline))
void Main_Circulation(void)
{
while(1)
{
TMOS_SystemProcess();
app_uart_process();
}
}
/*******************************************************************************
* Function Name : main
* Description : Main function
* Input : None
* Output : None
* Return : None
*******************************************************************************/
int main(void)
{
Delay_Init();
#ifdef DEBUG
USART_Printf_Init( 115200 );
#endif
PRINT("%s\n", VER_LIB);
WCHBLE_Init();
HAL_Init();
GAPRole_PeripheralInit();
Peripheral_Init();
app_uart_init();
Main_Circulation();
}
/******************************** endfile @ main ******************************/
+989
View File
@@ -0,0 +1,989 @@
/********************************** (C) COPYRIGHT *******************************
* File Name : system_ch32v20x.c
* Author : WCH
* Version : V1.0.0
* Date : 2021/06/06
* Description : CH32V20x Device Peripheral Access Layer System Source File.
* For HSE = 32Mhz (CH32V208x/CH32V203RBT6)
* For HSE = 8Mhz (other CH32V203x)
*********************************************************************************
* 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.
*******************************************************************************/
#include "ch32v20x.h"
/*
* Uncomment the line corresponding to the desired System clock (SYSCLK) frequency (after
* reset the HSI is used as SYSCLK source).
* If none of the define below is enabled, the HSI is used as System clock source.
*/
//#define SYSCLK_FREQ_HSE HSE_VALUE
//#define SYSCLK_FREQ_48MHz_HSE 48000000
//#define SYSCLK_FREQ_56MHz_HSE 56000000
//#define SYSCLK_FREQ_72MHz_HSE 72000000
#define SYSCLK_FREQ_96MHz_HSE 96000000
//#define SYSCLK_FREQ_120MHz_HSE 120000000
//#define SYSCLK_FREQ_144MHz_HSE 144000000
//#define SYSCLK_FREQ_HSI HSI_VALUE
//#define SYSCLK_FREQ_48MHz_HSI 48000000
//#define SYSCLK_FREQ_56MHz_HSI 56000000
//#define SYSCLK_FREQ_72MHz_HSI 72000000
//#define SYSCLK_FREQ_96MHz_HSI 96000000
//#define SYSCLK_FREQ_120MHz_HSI 120000000
//#define SYSCLK_FREQ_144MHz_HSI 144000000
/* Clock Definitions */
#ifdef SYSCLK_FREQ_HSE
uint32_t SystemCoreClock = SYSCLK_FREQ_HSE; /* System Clock Frequency (Core Clock) */
#elif defined SYSCLK_FREQ_48MHz_HSE
uint32_t SystemCoreClock = SYSCLK_FREQ_48MHz_HSE; /* System Clock Frequency (Core Clock) */
#elif defined SYSCLK_FREQ_56MHz_HSE
uint32_t SystemCoreClock = SYSCLK_FREQ_56MHz_HSE; /* System Clock Frequency (Core Clock) */
#elif defined SYSCLK_FREQ_72MHz_HSE
uint32_t SystemCoreClock = SYSCLK_FREQ_72MHz_HSE; /* System Clock Frequency (Core Clock) */
#elif defined SYSCLK_FREQ_96MHz_HSE
uint32_t SystemCoreClock = SYSCLK_FREQ_96MHz_HSE; /* System Clock Frequency (Core Clock) */
#elif defined SYSCLK_FREQ_120MHz_HSE
uint32_t SystemCoreClock = SYSCLK_FREQ_120MHz_HSE; /* System Clock Frequency (Core Clock) */
#elif defined SYSCLK_FREQ_144MHz_HSE
uint32_t SystemCoreClock = SYSCLK_FREQ_144MHz_HSE; /* System Clock Frequency (Core Clock) */
#elif defined SYSCLK_FREQ_48MHz_HSI
uint32_t SystemCoreClock = SYSCLK_FREQ_48MHz_HSI; /* System Clock Frequency (Core Clock) */
#elif defined SYSCLK_FREQ_56MHz_HSI
uint32_t SystemCoreClock = SYSCLK_FREQ_56MHz_HSI; /* System Clock Frequency (Core Clock) */
#elif defined SYSCLK_FREQ_72MHz_HSI
uint32_t SystemCoreClock = SYSCLK_FREQ_72MHz_HSI; /* System Clock Frequency (Core Clock) */
#elif defined SYSCLK_FREQ_96MHz_HSI
uint32_t SystemCoreClock = SYSCLK_FREQ_96MHz_HSI; /* System Clock Frequency (Core Clock) */
#elif defined SYSCLK_FREQ_120MHz_HSI
uint32_t SystemCoreClock = SYSCLK_FREQ_120MHz_HSI; /* System Clock Frequency (Core Clock) */
#elif defined SYSCLK_FREQ_144MHz_HSI
uint32_t SystemCoreClock = SYSCLK_FREQ_144MHz_HSI; /* System Clock Frequency (Core Clock) */
#else
uint32_t SystemCoreClock = HSI_VALUE; /* System Clock Frequency (Core Clock) */
#endif
__I uint8_t AHBPrescTable[16] = {0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 6, 7, 8, 9};
/* system_private_function_proto_types */
static void SetSysClock(void);
#ifdef SYSCLK_FREQ_HSE
static void SetSysClockToHSE( void );
#elif defined SYSCLK_FREQ_48MHz_HSE
static void SetSysClockTo48_HSE( void );
#elif defined SYSCLK_FREQ_56MHz_HSE
static void SetSysClockTo56_HSE( void );
#elif defined SYSCLK_FREQ_72MHz_HSE
static void SetSysClockTo72_HSE( void );
#elif defined SYSCLK_FREQ_96MHz_HSE
static void SetSysClockTo96_HSE( void );
#elif defined SYSCLK_FREQ_120MHz_HSE
static void SetSysClockTo120_HSE( void );
#elif defined SYSCLK_FREQ_144MHz_HSE
static void SetSysClockTo144_HSE( void );
#elif defined SYSCLK_FREQ_48MHz_HSI
static void SetSysClockTo48_HSI( void );
#elif defined SYSCLK_FREQ_56MHz_HSI
static void SetSysClockTo56_HSI( void );
#elif defined SYSCLK_FREQ_72MHz_HSI
static void SetSysClockTo72_HSI( void );
#elif defined SYSCLK_FREQ_96MHz_HSI
static void SetSysClockTo96_HSI( void );
#elif defined SYSCLK_FREQ_120MHz_HSI
static void SetSysClockTo120_HSI( void );
#elif defined SYSCLK_FREQ_144MHz_HSI
static void SetSysClockTo144_HSI( void );
#endif
/*********************************************************************
* @fn SystemInit
*
* @brief Setup the microcontroller system Initialize the Embedded Flash Interface,
* the PLL and update the SystemCoreClock variable.
*
* @return none
*/
void SystemInit (void)
{
RCC->CTLR |= (uint32_t)0x00000001;
RCC->CFGR0 &= (uint32_t)0xF8FF0000;
RCC->CTLR &= (uint32_t)0xFEF6FFFF;
RCC->CTLR &= (uint32_t)0xFFFBFFFF;
RCC->CFGR0 &= (uint32_t)0xFF80FFFF;
RCC->INTR = 0x009F0000;
SetSysClock();
}
/*********************************************************************
* @fn SystemCoreClockUpdate
*
* @brief Update SystemCoreClock variable according to Clock Register Values.
*
* @return none
*/
void SystemCoreClockUpdate (void)
{
uint32_t tmp = 0, pllmull = 0, pllsource = 0, Pll_6_5 = 0;
tmp = RCC->CFGR0 & RCC_SWS;
switch (tmp)
{
case 0x00:
SystemCoreClock = HSI_VALUE;
break;
case 0x04:
SystemCoreClock = HSE_VALUE;
break;
case 0x08:
pllmull = RCC->CFGR0 & RCC_PLLMULL;
pllsource = RCC->CFGR0 & RCC_PLLSRC;
pllmull = ( pllmull >> 18) + 2;
if(pllmull == 17) pllmull = 18;
if (pllsource == 0x00)
{
if(EXTEN->EXTEN_CTR & EXTEN_PLL_HSI_PRE){
SystemCoreClock = HSI_VALUE * pllmull;
}
else{
SystemCoreClock = (HSI_VALUE >> 1) * pllmull;
}
}
else
{
#if defined (CH32V20x_D8W)
if((RCC->CFGR0 & (3<<22)) == (3<<22))
{
SystemCoreClock = ((HSE_VALUE>>1)) * pllmull;
}
else
#endif
if ((RCC->CFGR0 & RCC_PLLXTPRE) != (uint32_t)RESET)
{
#if defined (CH32V20x_D8) || defined (CH32V20x_D8W)
SystemCoreClock = ((HSE_VALUE>>2) >> 1) * pllmull;
#else
SystemCoreClock = (HSE_VALUE >> 1) * pllmull;
#endif
}
else
{
#if defined (CH32V20x_D8) || defined (CH32V20x_D8W)
SystemCoreClock = (HSE_VALUE>>2) * pllmull;
#else
SystemCoreClock = HSE_VALUE * pllmull;
#endif
}
}
if(Pll_6_5 == 1) SystemCoreClock = (SystemCoreClock / 2);
break;
default:
SystemCoreClock = HSI_VALUE;
break;
}
tmp = AHBPrescTable[((RCC->CFGR0 & RCC_HPRE) >> 4)];
SystemCoreClock >>= tmp;
}
/*********************************************************************
* @fn SetSysClock
*
* @brief Configures the System clock frequency, HCLK, PCLK2 and PCLK1 prescalers.
*
* @return none
*/
static void SetSysClock(void)
{
#ifdef SYSCLK_FREQ_HSE
SetSysClockToHSE();
#elif defined SYSCLK_FREQ_48MHz_HSE
SetSysClockTo48_HSE();
#elif defined SYSCLK_FREQ_56MHz_HSE
SetSysClockTo56_HSE();
#elif defined SYSCLK_FREQ_72MHz_HSE
SetSysClockTo72_HSE();
#elif defined SYSCLK_FREQ_96MHz_HSE
SetSysClockTo96_HSE();
#elif defined SYSCLK_FREQ_120MHz_HSE
SetSysClockTo120_HSE();
#elif defined SYSCLK_FREQ_144MHz_HSE
SetSysClockTo144_HSE();
#elif defined SYSCLK_FREQ_48MHz_HSI
SetSysClockTo48_HSI();
#elif defined SYSCLK_FREQ_56MHz_HSI
SetSysClockTo56_HSI();
#elif defined SYSCLK_FREQ_72MHz_HSI
SetSysClockTo72_HSI();
#elif defined SYSCLK_FREQ_96MHz_HSI
SetSysClockTo96_HSI();
#elif defined SYSCLK_FREQ_120MHz_HSI
SetSysClockTo120_HSI();
#elif defined SYSCLK_FREQ_144MHz_HSI
SetSysClockTo144_HSI();
#endif
/* If none of the define above is enabled, the HSI is used as System clock
* source (default after reset)
*/
}
#ifdef SYSCLK_FREQ_HSE
/*********************************************************************
* @fn SetSysClockToHSE
*
* @brief Sets HSE as System clock source and configure HCLK, PCLK2 and PCLK1 prescalers.
*
* @return none
*/
static void SetSysClockToHSE(void)
{
__IO uint32_t StartUpCounter = 0, HSEStatus = 0;
RCC->CTLR |= ((uint32_t)RCC_HSEON);
/* Wait till HSE is ready and if Time out is reached exit */
do
{
HSEStatus = RCC->CTLR & RCC_HSERDY;
StartUpCounter++;
} while((HSEStatus == 0) && (StartUpCounter != HSE_STARTUP_TIMEOUT));
if ((RCC->CTLR & RCC_HSERDY) != RESET)
{
HSEStatus = (uint32_t)0x01;
}
else
{
HSEStatus = (uint32_t)0x00;
}
if (HSEStatus == (uint32_t)0x01)
{
/* HCLK = SYSCLK */
RCC->CFGR0 |= (uint32_t)RCC_HPRE_DIV1;
/* PCLK2 = HCLK */
RCC->CFGR0 |= (uint32_t)RCC_PPRE2_DIV1;
/* PCLK1 = HCLK */
RCC->CFGR0 |= (uint32_t)RCC_PPRE1_DIV1;
/* Select HSE as system clock source
* CH32V20x_D6 (HSE=8MHZ)
* CH32V20x_D8 (HSE=32MHZ)
* CH32V20x_D8W (HSE=32MHZ)
*/
RCC->CFGR0 &= (uint32_t)((uint32_t)~(RCC_SW));
RCC->CFGR0 |= (uint32_t)RCC_SW_HSE;
/* Wait till HSE is used as system clock source */
while ((RCC->CFGR0 & (uint32_t)RCC_SWS) != (uint32_t)0x04)
{
}
}
else
{
/* If HSE fails to start-up, the application will have wrong clock
* configuration. User can add here some code to deal with this error
*/
}
}
#elif defined SYSCLK_FREQ_48MHz_HSE
/*********************************************************************
* @fn SetSysClockTo48_HSE
*
* @brief Sets System clock frequency to 48MHz and configure HCLK, PCLK2 and PCLK1 prescalers.
*
* @return none
*/
static void SetSysClockTo48_HSE(void)
{
__IO uint32_t StartUpCounter = 0, HSEStatus = 0;
RCC->CTLR |= ((uint32_t)RCC_HSEON);
/* Wait till HSE is ready and if Time out is reached exit */
do
{
HSEStatus = RCC->CTLR & RCC_HSERDY;
StartUpCounter++;
} while((HSEStatus == 0) && (StartUpCounter != HSE_STARTUP_TIMEOUT));
if ((RCC->CTLR & RCC_HSERDY) != RESET)
{
HSEStatus = (uint32_t)0x01;
}
else
{
HSEStatus = (uint32_t)0x00;
}
if (HSEStatus == (uint32_t)0x01)
{
/* HCLK = SYSCLK */
RCC->CFGR0 |= (uint32_t)RCC_HPRE_DIV1;
/* PCLK2 = HCLK */
RCC->CFGR0 |= (uint32_t)RCC_PPRE2_DIV1;
/* PCLK1 = HCLK */
RCC->CFGR0 |= (uint32_t)RCC_PPRE1_DIV2;
/* CH32V20x_D6-PLL configuration: PLLCLK = HSE * 6 = 48 MHz (HSE=8MHZ)
* CH32V20x_D8-PLL configuration: PLLCLK = HSE/4 * 6 = 48 MHz (HSE=32MHZ)
* CH32V20x_D8W-PLL configuration: PLLCLK = HSE/4 * 6 = 48 MHz (HSE=32MHZ)
*/
RCC->CFGR0 &= (uint32_t)((uint32_t)~(RCC_PLLSRC | RCC_PLLXTPRE | RCC_PLLMULL));
RCC->CFGR0 |= (uint32_t)(RCC_PLLSRC_HSE | RCC_PLLXTPRE_HSE | RCC_PLLMULL6);
/* Enable PLL */
RCC->CTLR |= RCC_PLLON;
/* Wait till PLL is ready */
while((RCC->CTLR & RCC_PLLRDY) == 0)
{
}
/* Select PLL as system clock source */
RCC->CFGR0 &= (uint32_t)((uint32_t)~(RCC_SW));
RCC->CFGR0 |= (uint32_t)RCC_SW_PLL;
/* Wait till PLL is used as system clock source */
while ((RCC->CFGR0 & (uint32_t)RCC_SWS) != (uint32_t)0x08)
{
}
}
else
{
/*
* If HSE fails to start-up, the application will have wrong clock
* configuration. User can add here some code to deal with this error
*/
}
}
#elif defined SYSCLK_FREQ_56MHz_HSE
/*********************************************************************
* @fn SetSysClockTo56_HSE
*
* @brief Sets System clock frequency to 56MHz and configure HCLK, PCLK2 and PCLK1 prescalers.
*
* @return none
*/
static void SetSysClockTo56_HSE(void)
{
__IO uint32_t StartUpCounter = 0, HSEStatus = 0;
RCC->CTLR |= ((uint32_t)RCC_HSEON);
/* Wait till HSE is ready and if Time out is reached exit */
do
{
HSEStatus = RCC->CTLR & RCC_HSERDY;
StartUpCounter++;
} while((HSEStatus == 0) && (StartUpCounter != HSE_STARTUP_TIMEOUT));
if ((RCC->CTLR & RCC_HSERDY) != RESET)
{
HSEStatus = (uint32_t)0x01;
}
else
{
HSEStatus = (uint32_t)0x00;
}
if (HSEStatus == (uint32_t)0x01)
{
/* HCLK = SYSCLK */
RCC->CFGR0 |= (uint32_t)RCC_HPRE_DIV1;
/* PCLK2 = HCLK */
RCC->CFGR0 |= (uint32_t)RCC_PPRE2_DIV1;
/* PCLK1 = HCLK */
RCC->CFGR0 |= (uint32_t)RCC_PPRE1_DIV2;
/* CH32V20x_D6-PLL configuration: PLLCLK = HSE * 7 = 56 MHz (HSE=8MHZ)
* CH32V20x_D8-PLL configuration: PLLCLK = HSE/4 * 7 = 56 MHz (HSE=32MHZ)
* CH32V20x_D8W-PLL configuration: PLLCLK = HSE/4 * 7 = 56 MHz (HSE=32MHZ)
*/
RCC->CFGR0 &= (uint32_t)((uint32_t)~(RCC_PLLSRC | RCC_PLLXTPRE | RCC_PLLMULL));
RCC->CFGR0 |= (uint32_t)(RCC_PLLSRC_HSE | RCC_PLLXTPRE_HSE | RCC_PLLMULL7);
/* Enable PLL */
RCC->CTLR |= RCC_PLLON;
/* Wait till PLL is ready */
while((RCC->CTLR & RCC_PLLRDY) == 0)
{
}
/* Select PLL as system clock source */
RCC->CFGR0 &= (uint32_t)((uint32_t)~(RCC_SW));
RCC->CFGR0 |= (uint32_t)RCC_SW_PLL;
/* Wait till PLL is used as system clock source */
while ((RCC->CFGR0 & (uint32_t)RCC_SWS) != (uint32_t)0x08)
{
}
}
else
{
/*
* If HSE fails to start-up, the application will have wrong clock
* configuration. User can add here some code to deal with this error
*/
}
}
#elif defined SYSCLK_FREQ_72MHz_HSE
/*********************************************************************
* @fn SetSysClockTo72_HSE
*
* @brief Sets System clock frequency to 72MHz and configure HCLK, PCLK2 and PCLK1 prescalers.
*
* @return none
*/
static void SetSysClockTo72_HSE(void)
{
__IO uint32_t StartUpCounter = 0, HSEStatus = 0;
RCC->CTLR |= ((uint32_t)RCC_HSEON);
/* Wait till HSE is ready and if Time out is reached exit */
do
{
HSEStatus = RCC->CTLR & RCC_HSERDY;
StartUpCounter++;
} while((HSEStatus == 0) && (StartUpCounter != HSE_STARTUP_TIMEOUT));
if ((RCC->CTLR & RCC_HSERDY) != RESET)
{
HSEStatus = (uint32_t)0x01;
}
else
{
HSEStatus = (uint32_t)0x00;
}
if (HSEStatus == (uint32_t)0x01)
{
/* HCLK = SYSCLK */
RCC->CFGR0 |= (uint32_t)RCC_HPRE_DIV1;
/* PCLK2 = HCLK */
RCC->CFGR0 |= (uint32_t)RCC_PPRE2_DIV1;
/* PCLK1 = HCLK */
RCC->CFGR0 |= (uint32_t)RCC_PPRE1_DIV2;
/* CH32V20x_D6-PLL configuration: PLLCLK = HSE * 9 = 72 MHz (HSE=8MHZ)
* CH32V20x_D8-PLL configuration: PLLCLK = HSE/4 * 9 = 72 MHz (HSE=32MHZ)
* CH32V20x_D8W-PLL configuration: PLLCLK = HSE/4 * 9 = 72 MHz (HSE=32MHZ)
*/
RCC->CFGR0 &= (uint32_t)((uint32_t)~(RCC_PLLSRC | RCC_PLLXTPRE |
RCC_PLLMULL));
RCC->CFGR0 |= (uint32_t)(RCC_PLLSRC_HSE | RCC_PLLXTPRE_HSE | RCC_PLLMULL9);
/* Enable PLL */
RCC->CTLR |= RCC_PLLON;
/* Wait till PLL is ready */
while((RCC->CTLR & RCC_PLLRDY) == 0)
{
}
/* Select PLL as system clock source */
RCC->CFGR0 &= (uint32_t)((uint32_t)~(RCC_SW));
RCC->CFGR0 |= (uint32_t)RCC_SW_PLL;
/* Wait till PLL is used as system clock source */
while ((RCC->CFGR0 & (uint32_t)RCC_SWS) != (uint32_t)0x08)
{
}
}
else
{
/*
* If HSE fails to start-up, the application will have wrong clock
* configuration. User can add here some code to deal with this error
*/
}
}
#elif defined SYSCLK_FREQ_96MHz_HSE
/*********************************************************************
* @fn SetSysClockTo96_HSE
*
* @brief Sets System clock frequency to 96MHz and configure HCLK, PCLK2 and PCLK1 prescalers.
*
* @return none
*/
static void SetSysClockTo96_HSE(void)
{
__IO uint32_t StartUpCounter = 0, HSEStatus = 0;
RCC->CTLR |= ((uint32_t)RCC_HSEON);
/* Wait till HSE is ready and if Time out is reached exit */
do
{
HSEStatus = RCC->CTLR & RCC_HSERDY;
StartUpCounter++;
} while((HSEStatus == 0) && (StartUpCounter != HSE_STARTUP_TIMEOUT));
if ((RCC->CTLR & RCC_HSERDY) != RESET)
{
HSEStatus = (uint32_t)0x01;
}
else
{
HSEStatus = (uint32_t)0x00;
}
if (HSEStatus == (uint32_t)0x01)
{
/* HCLK = SYSCLK */
RCC->CFGR0 |= (uint32_t)RCC_HPRE_DIV1;
/* PCLK2 = HCLK */
RCC->CFGR0 |= (uint32_t)RCC_PPRE2_DIV1;
/* PCLK1 = HCLK */
RCC->CFGR0 |= (uint32_t)RCC_PPRE1_DIV2;
/* CH32V20x_D6-PLL configuration: PLLCLK = HSE * 12 = 96 MHz (HSE=8MHZ)
* CH32V20x_D8-PLL configuration: PLLCLK = HSE/4 * 12 = 96 MHz (HSE=32MHZ)
* CH32V20x_D8W-PLL configuration: PLLCLK = HSE/4 * 12 = 96 MHz (HSE=32MHZ)
*/
RCC->CFGR0 &= (uint32_t)((uint32_t)~(RCC_PLLSRC | RCC_PLLXTPRE |
RCC_PLLMULL));
RCC->CFGR0 |= (uint32_t)(RCC_PLLSRC_HSE | RCC_PLLXTPRE_HSE | RCC_PLLMULL12);
/* Enable PLL */
RCC->CTLR |= RCC_PLLON;
/* Wait till PLL is ready */
while((RCC->CTLR & RCC_PLLRDY) == 0)
{
}
/* Select PLL as system clock source */
RCC->CFGR0 &= (uint32_t)((uint32_t)~(RCC_SW));
RCC->CFGR0 |= (uint32_t)RCC_SW_PLL;
/* Wait till PLL is used as system clock source */
while ((RCC->CFGR0 & (uint32_t)RCC_SWS) != (uint32_t)0x08)
{
}
}
else
{
/*
* If HSE fails to start-up, the application will have wrong clock
* configuration. User can add here some code to deal with this error
*/
}
}
#elif defined SYSCLK_FREQ_120MHz_HSE
/*********************************************************************
* @fn SetSysClockTo120_HSE
*
* @brief Sets System clock frequency to 120MHz and configure HCLK, PCLK2 and PCLK1 prescalers.
*
* @return none
*/
static void SetSysClockTo120_HSE(void)
{
__IO uint32_t StartUpCounter = 0, HSEStatus = 0;
RCC->CTLR |= ((uint32_t)RCC_HSEON);
/* Wait till HSE is ready and if Time out is reached exit */
do
{
HSEStatus = RCC->CTLR & RCC_HSERDY;
StartUpCounter++;
} while((HSEStatus == 0) && (StartUpCounter != HSE_STARTUP_TIMEOUT));
if((RCC->CTLR & RCC_HSERDY) != RESET)
{
HSEStatus = (uint32_t)0x01;
}
else
{
HSEStatus = (uint32_t)0x00;
}
if(HSEStatus == (uint32_t)0x01)
{
#if defined (CH32V20x_D8W)
RCC->CFGR0 |= (uint32_t)(3<<22);
/* HCLK = SYSCLK/2 */
RCC->CFGR0 |= (uint32_t)RCC_HPRE_DIV2;
#else
/* HCLK = SYSCLK */
RCC->CFGR0 |= (uint32_t)RCC_HPRE_DIV1;
#endif
/* PCLK2 = HCLK */
RCC->CFGR0 |= (uint32_t)RCC_PPRE2_DIV1;
/* PCLK1 = HCLK */
RCC->CFGR0 |= (uint32_t)RCC_PPRE1_DIV2;
/* CH32V20x_D6-PLL configuration: PLLCLK = HSE * 15 = 120 MHz (HSE=8MHZ)
* CH32V20x_D8-PLL configuration: PLLCLK = HSE/4 * 15 = 120 MHz (HSE=32MHZ)
* CH32V20x_D8W-PLL configuration: PLLCLK = HSE/2 * 15 = 240 MHz (HSE=32MHZ)
*/
RCC->CFGR0 &= (uint32_t)((uint32_t) ~(RCC_PLLSRC | RCC_PLLXTPRE |
RCC_PLLMULL));
RCC->CFGR0 |= (uint32_t)(RCC_PLLSRC_HSE | RCC_PLLXTPRE_HSE | RCC_PLLMULL15);
/* Enable PLL */
RCC->CTLR |= RCC_PLLON;
/* Wait till PLL is ready */
while((RCC->CTLR & RCC_PLLRDY) == 0)
{
}
/* Select PLL as system clock source */
RCC->CFGR0 &= (uint32_t)((uint32_t) ~(RCC_SW));
RCC->CFGR0 |= (uint32_t)RCC_SW_PLL;
/* Wait till PLL is used as system clock source */
while((RCC->CFGR0 & (uint32_t)RCC_SWS) != (uint32_t)0x08)
{
}
}
else
{
/*
* If HSE fails to start-up, the application will have wrong clock
* configuration. User can add here some code to deal with this error
*/
}
}
#elif defined SYSCLK_FREQ_144MHz_HSE
/*********************************************************************
* @fn SetSysClockTo144_HSE
*
* @brief Sets System clock frequency to 144MHz and configure HCLK, PCLK2 and PCLK1 prescalers.
*
* @return none
*/
static void SetSysClockTo144_HSE(void)
{
__IO uint32_t StartUpCounter = 0, HSEStatus = 0;
RCC->CTLR |= ((uint32_t)RCC_HSEON);
/* Wait till HSE is ready and if Time out is reached exit */
do
{
HSEStatus = RCC->CTLR & RCC_HSERDY;
StartUpCounter++;
} while((HSEStatus == 0) && (StartUpCounter != HSE_STARTUP_TIMEOUT));
if ((RCC->CTLR & RCC_HSERDY) != RESET)
{
HSEStatus = (uint32_t)0x01;
}
else
{
HSEStatus = (uint32_t)0x00;
}
if (HSEStatus == (uint32_t)0x01)
{
/* HCLK = SYSCLK */
RCC->CFGR0 |= (uint32_t)RCC_HPRE_DIV1;
/* PCLK2 = HCLK */
RCC->CFGR0 |= (uint32_t)RCC_PPRE2_DIV1;
/* PCLK1 = HCLK */
RCC->CFGR0 |= (uint32_t)RCC_PPRE1_DIV2;
/* CH32V20x_D6-PLL configuration: PLLCLK = HSE * 18 = 144 MHz (HSE=8MHZ)
* CH32V20x_D8-PLL configuration: PLLCLK = HSE/4 * 18 = 144 MHz (HSE=32MHZ)
* CH32V20x_D8W-PLL configuration: PLLCLK = HSE/4 * 18 = 144 MHz (HSE=32MHZ)
*/
RCC->CFGR0 &= (uint32_t)((uint32_t)~(RCC_PLLSRC | RCC_PLLXTPRE |
RCC_PLLMULL));
RCC->CFGR0 |= (uint32_t)(RCC_PLLSRC_HSE | RCC_PLLXTPRE_HSE | RCC_PLLMULL18);
/* Enable PLL */
RCC->CTLR |= RCC_PLLON;
/* Wait till PLL is ready */
while((RCC->CTLR & RCC_PLLRDY) == 0)
{
}
/* Select PLL as system clock source */
RCC->CFGR0 &= (uint32_t)((uint32_t)~(RCC_SW));
RCC->CFGR0 |= (uint32_t)RCC_SW_PLL;
/* Wait till PLL is used as system clock source */
while ((RCC->CFGR0 & (uint32_t)RCC_SWS) != (uint32_t)0x08)
{
}
}
else
{
/*
* If HSE fails to start-up, the application will have wrong clock
* configuration. User can add here some code to deal with this error
*/
}
}
#elif defined SYSCLK_FREQ_48MHz_HSI
/*********************************************************************
* @fn SetSysClockTo48_HSI
*
* @brief Sets System clock frequency to 48MHz and configure HCLK, PCLK2 and PCLK1 prescalers.
*
* @return none
*/
static void SetSysClockTo48_HSI(void)
{
EXTEN->EXTEN_CTR |= EXTEN_PLL_HSI_PRE;
/* HCLK = SYSCLK */
RCC->CFGR0 |= (uint32_t)RCC_HPRE_DIV1;
/* PCLK2 = HCLK */
RCC->CFGR0 |= (uint32_t)RCC_PPRE2_DIV1;
/* PCLK1 = HCLK */
RCC->CFGR0 |= (uint32_t)RCC_PPRE1_DIV2;
/* PLL configuration: PLLCLK = HSI * 6 = 48 MHz */
RCC->CFGR0 &= (uint32_t)((uint32_t)~(RCC_PLLSRC | RCC_PLLXTPRE | RCC_PLLMULL));
RCC->CFGR0 |= (uint32_t)(RCC_PLLSRC_HSI_Div2 | RCC_PLLMULL6);
/* Enable PLL */
RCC->CTLR |= RCC_PLLON;
/* Wait till PLL is ready */
while((RCC->CTLR & RCC_PLLRDY) == 0)
{
}
/* Select PLL as system clock source */
RCC->CFGR0 &= (uint32_t)((uint32_t)~(RCC_SW));
RCC->CFGR0 |= (uint32_t)RCC_SW_PLL;
/* Wait till PLL is used as system clock source */
while ((RCC->CFGR0 & (uint32_t)RCC_SWS) != (uint32_t)0x08)
{
}
}
#elif defined SYSCLK_FREQ_56MHz_HSI
/*********************************************************************
* @fn SetSysClockTo56_HSI
*
* @brief Sets System clock frequency to 56MHz and configure HCLK, PCLK2 and PCLK1 prescalers.
*
* @return none
*/
static void SetSysClockTo56_HSI(void)
{
EXTEN->EXTEN_CTR |= EXTEN_PLL_HSI_PRE;
/* HCLK = SYSCLK */
RCC->CFGR0 |= (uint32_t)RCC_HPRE_DIV1;
/* PCLK2 = HCLK */
RCC->CFGR0 |= (uint32_t)RCC_PPRE2_DIV1;
/* PCLK1 = HCLK */
RCC->CFGR0 |= (uint32_t)RCC_PPRE1_DIV2;
/* PLL configuration: PLLCLK = HSI * 7 = 48 MHz */
RCC->CFGR0 &= (uint32_t)((uint32_t)~(RCC_PLLSRC | RCC_PLLXTPRE | RCC_PLLMULL));
RCC->CFGR0 |= (uint32_t)(RCC_PLLSRC_HSI_Div2 | RCC_PLLMULL7);
/* Enable PLL */
RCC->CTLR |= RCC_PLLON;
/* Wait till PLL is ready */
while((RCC->CTLR & RCC_PLLRDY) == 0)
{
}
/* Select PLL as system clock source */
RCC->CFGR0 &= (uint32_t)((uint32_t)~(RCC_SW));
RCC->CFGR0 |= (uint32_t)RCC_SW_PLL;
/* Wait till PLL is used as system clock source */
while ((RCC->CFGR0 & (uint32_t)RCC_SWS) != (uint32_t)0x08)
{
}
}
#elif defined SYSCLK_FREQ_72MHz_HSI
/*********************************************************************
* @fn SetSysClockTo72_HSI
*
* @brief Sets System clock frequency to 72MHz and configure HCLK, PCLK2 and PCLK1 prescalers.
*
* @return none
*/
static void SetSysClockTo72_HSI(void)
{
EXTEN->EXTEN_CTR |= EXTEN_PLL_HSI_PRE;
/* HCLK = SYSCLK */
RCC->CFGR0 |= (uint32_t)RCC_HPRE_DIV1;
/* PCLK2 = HCLK */
RCC->CFGR0 |= (uint32_t)RCC_PPRE2_DIV1;
/* PCLK1 = HCLK */
RCC->CFGR0 |= (uint32_t)RCC_PPRE1_DIV2;
/* PLL configuration: PLLCLK = HSI * 9 = 72 MHz */
RCC->CFGR0 &= (uint32_t)((uint32_t)~(RCC_PLLSRC | RCC_PLLXTPRE | RCC_PLLMULL));
RCC->CFGR0 |= (uint32_t)(RCC_PLLSRC_HSI_Div2 | RCC_PLLMULL9);
/* Enable PLL */
RCC->CTLR |= RCC_PLLON;
/* Wait till PLL is ready */
while((RCC->CTLR & RCC_PLLRDY) == 0)
{
}
/* Select PLL as system clock source */
RCC->CFGR0 &= (uint32_t)((uint32_t)~(RCC_SW));
RCC->CFGR0 |= (uint32_t)RCC_SW_PLL;
/* Wait till PLL is used as system clock source */
while ((RCC->CFGR0 & (uint32_t)RCC_SWS) != (uint32_t)0x08)
{
}
}
#elif defined SYSCLK_FREQ_96MHz_HSI
/*********************************************************************
* @fn SetSysClockTo96_HSI
*
* @brief Sets System clock frequency to 96MHz and configure HCLK, PCLK2 and PCLK1 prescalers.
*
* @return none
*/
static void SetSysClockTo96_HSI(void)
{
EXTEN->EXTEN_CTR |= EXTEN_PLL_HSI_PRE;
/* HCLK = SYSCLK */
RCC->CFGR0 |= (uint32_t)RCC_HPRE_DIV1;
/* PCLK2 = HCLK */
RCC->CFGR0 |= (uint32_t)RCC_PPRE2_DIV1;
/* PCLK1 = HCLK */
RCC->CFGR0 |= (uint32_t)RCC_PPRE1_DIV2;
/* PLL configuration: PLLCLK = HSI * 12 = 96 MHz */
RCC->CFGR0 &= (uint32_t)((uint32_t)~(RCC_PLLSRC | RCC_PLLXTPRE | RCC_PLLMULL));
RCC->CFGR0 |= (uint32_t)(RCC_PLLSRC_HSI_Div2 | RCC_PLLMULL12);
/* Enable PLL */
RCC->CTLR |= RCC_PLLON;
/* Wait till PLL is ready */
while((RCC->CTLR & RCC_PLLRDY) == 0)
{
}
/* Select PLL as system clock source */
RCC->CFGR0 &= (uint32_t)((uint32_t)~(RCC_SW));
RCC->CFGR0 |= (uint32_t)RCC_SW_PLL;
/* Wait till PLL is used as system clock source */
while ((RCC->CFGR0 & (uint32_t)RCC_SWS) != (uint32_t)0x08)
{
}
}
#elif defined SYSCLK_FREQ_120MHz_HSI
/*********************************************************************
* @fn SetSysClockTo120_HSI
*
* @brief Sets System clock frequency to 120MHz and configure HCLK, PCLK2 and PCLK1 prescalers.
*
* @return none
*/
static void SetSysClockTo120_HSI(void)
{
EXTEN->EXTEN_CTR |= EXTEN_PLL_HSI_PRE;
/* HCLK = SYSCLK */
RCC->CFGR0 |= (uint32_t)RCC_HPRE_DIV1;
/* PCLK2 = HCLK */
RCC->CFGR0 |= (uint32_t)RCC_PPRE2_DIV1;
/* PCLK1 = HCLK */
RCC->CFGR0 |= (uint32_t)RCC_PPRE1_DIV2;
/* PLL configuration: PLLCLK = HSI * 15 = 120 MHz */
RCC->CFGR0 &= (uint32_t)((uint32_t) ~(RCC_PLLSRC | RCC_PLLXTPRE |
RCC_PLLMULL));
RCC->CFGR0 |= (uint32_t)(RCC_PLLSRC_HSI_Div2 | RCC_PLLMULL15);
/* Enable PLL */
RCC->CTLR |= RCC_PLLON;
/* Wait till PLL is ready */
while((RCC->CTLR & RCC_PLLRDY) == 0)
{
}
/* Select PLL as system clock source */
RCC->CFGR0 &= (uint32_t)((uint32_t) ~(RCC_SW));
RCC->CFGR0 |= (uint32_t)RCC_SW_PLL;
/* Wait till PLL is used as system clock source */
while((RCC->CFGR0 & (uint32_t)RCC_SWS) != (uint32_t)0x08)
{
}
}
#elif defined SYSCLK_FREQ_144MHz_HSI
/*********************************************************************
* @fn SetSysClockTo144_HSI
*
* @brief Sets System clock frequency to 144MHz and configure HCLK, PCLK2 and PCLK1 prescalers.
*
* @return none
*/
static void SetSysClockTo144_HSI(void)
{
EXTEN->EXTEN_CTR |= EXTEN_PLL_HSI_PRE;
/* HCLK = SYSCLK */
RCC->CFGR0 |= (uint32_t)RCC_HPRE_DIV1;
/* PCLK2 = HCLK */
RCC->CFGR0 |= (uint32_t)RCC_PPRE2_DIV1;
/* PCLK1 = HCLK */
RCC->CFGR0 |= (uint32_t)RCC_PPRE1_DIV2;
/* PLL configuration: PLLCLK = HSI * 18 = 144 MHz */
RCC->CFGR0 &= (uint32_t)((uint32_t)~(RCC_PLLSRC | RCC_PLLXTPRE | RCC_PLLMULL));
RCC->CFGR0 |= (uint32_t)(RCC_PLLSRC_HSI_Div2 | RCC_PLLMULL18);
/* Enable PLL */
RCC->CTLR |= RCC_PLLON;
/* Wait till PLL is ready */
while((RCC->CTLR & RCC_PLLRDY) == 0)
{
}
/* Select PLL as system clock source */
RCC->CFGR0 &= (uint32_t)((uint32_t)~(RCC_SW));
RCC->CFGR0 |= (uint32_t)RCC_SW_PLL;
/* Wait till PLL is used as system clock source */
while ((RCC->CFGR0 & (uint32_t)RCC_SWS) != (uint32_t)0x08)
{
}
}
#endif