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,909 @@
/*
* 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 "ancs_client.h"
#include "ancs_client_internal.h"
#include "ancs.h"
/*********************************************************************
* MACROS
*/
// Length of bd addr as a string
#define B_ADDR_STR_LEN 15
/*********************************************************************
* CONSTANTS
*/
// What is the advertising interval when device is discoverable (units of 625us, 80=50ms)
#define DEFAULT_ADVERTISING_INTERVAL 80
// Minimum connection interval (units of 1.25ms, 6=7.5ms)
#define DEFAULT_DESIRED_MIN_CONN_INTERVAL 6
// Maximum connection interval (units of 1.25ms, 100=125ms)
#define DEFAULT_DESIRED_MAX_CONN_INTERVAL 100
// Slave latency to use parameter update
#define DEFAULT_DESIRED_SLAVE_LATENCY 0
// Minimum connection interval (units of 1.25ms)
#define DEFAULT_UPDATE_MIN_CONN_INTERVAL 24
// Maximum connection interval (units of 1.25ms)
#define DEFAULT_UPDATE_MAX_CONN_INTERVAL 40
// Slave latency to use parameter update
#define DEFAULT_UPDATE_SLAVE_LATENCY 0
// Supervision timeout value (units of 10ms)
#define DEFAULT_UPDATE_CONN_TIMEOUT 42
// Default parameter update delay in 0.625ms
#define DEFAULT_PARAM_UPDATE_DELAY 3200
// Default phy update delay in 0.625ms
#define DEFAULT_PHY_UPDATE_DELAY 2400
// ANCS Service: 7905F431-B5CE-4E99-A40F-4B1E122D00D0
#define ANCS_SVC_UUID 0xD0, 0x00, 0x2D, 0x12, 0x1E, 0x4B, 0x0F, 0xA4, 0x99, 0x4E, 0xCE, 0xB5, 0x31, 0xF4, 0x05, 0x79
// Notification Source: UUID 9FBF120D-6301-42D9-8C58-25E699A21DBD (notifiable)
#define ANCS_NOTIF_SRC_CHAR_UUID 0x1DBD // Last 2 bytes of the 128bit-16bytes UUID
// Control point: UUID 69D1D8F3-45E1-49A8-9821-9BBDFDAAD9D9 (writeable with response)
#define ANCS_CTRL_PT_CHAR_UUID 0xD9D9
// Data Source: UUID 22EAC6E9-24D6-4BB5-BE44-B36ACE7C7BFB (notifiable)
#define ANCS_DATA_SRC_CHAR_UUID 0x7BFB
#define CHAR_DESC_HDL_UUID128_LEN 21 // 5 + 16bytes = 21
/*********************************************************************
* TYPEDEFS
*/
/*********************************************************************
* GLOBAL VARIABLES
*/
uint16_t Ancs_handleCache[HDL_CACHE_LEN];
// Task ID for internal task/event processing
uint8_t ancs_taskid;
/*********************************************************************
* EXTERNAL VARIABLES
*/
/*********************************************************************
* EXTERNAL FUNCTIONS
*/
/*********************************************************************
* LOCAL VARIABLES
*/
struct bt_ancs_client ancs_c;
// GAP - SCAN RSP data (max size = 31 bytes)
static uint8_t scanRspData[] = {
// complete name
0x05, // length of this data
GAP_ADTYPE_LOCAL_NAME_COMPLETE,
'A',
'N',
'C',
'S',
// connection interval range
0x05, // length of this data
GAP_ADTYPE_SLAVE_CONN_INTERVAL_RANGE,
LO_UINT16(DEFAULT_DESIRED_MIN_CONN_INTERVAL), // 100ms
HI_UINT16(DEFAULT_DESIRED_MIN_CONN_INTERVAL),
LO_UINT16(DEFAULT_DESIRED_MAX_CONN_INTERVAL), // 1s
HI_UINT16(DEFAULT_DESIRED_MAX_CONN_INTERVAL),
// Tx power level
0x02, // length of this data
GAP_ADTYPE_POWER_LEVEL,
0 // 0dBm
};
// GAP - Advertisement data (max size = 31 bytes, though this is
// best kept short to conserve power while advertising)
static uint8_t advertData[] = {
// Flags; this sets the device to use limited discoverable
// mode (advertises for 30 seconds at a time) instead of general
// discoverable mode (advertises indefinitely)
0x02, // length of this data
GAP_ADTYPE_FLAGS,
GAP_ADTYPE_FLAGS_LIMITED | GAP_ADTYPE_FLAGS_BREDR_NOT_SUPPORTED,
// service UUID, to notify central devices what services are included
// in this peripheral
0x11, // length of this data
GAP_ADTYPE_SERVICES_LIST_128BIT, // some of the UUID's, but not all
ANCS_SVC_UUID,
0x05,
GAP_ADTYPE_LOCAL_NAME_COMPLETE,
'A', 'N', 'C', 'S',
};
// Connection handle of current connection
static peripheralConnItem_t ancs_conn_list = {
.connHandle = GAP_CONNHANDLE_INIT
};
static uint8_t discoveryState = DISC_ANCS_START;
// GAP GATT Attributes
static uint8_t attDeviceName[GAP_DEVICE_NAME_LEN] = "ANCS";
/*********************************************************************
* LOCAL FUNCTIONS
*/
uint16_t ANCS_ProcessEvent(uint8_t task_id, uint16_t events);
static void AncsProcessTMOSMsg(tmos_event_hdr_t *pMsg);
static void AncsApp_discoverService(gattMsgEvent_t *pMsg);
static void AncsStateNotificationCB(gapRole_States_t newState, gapRoleEvent_t *pEvent);
static void AncsParamUpdateCB(uint16_t connHandle, uint16_t connInterval,
uint16_t connSlaveLatency, uint16_t connTimeout);
static void AncsPasscodeCB(uint8_t *deviceAddr, uint16_t connectionHandle,
uint8_t uiInputs, uint8_t uiOutputs);
static void AncsPairStateCB(uint16_t connHandle, uint8_t state, uint8_t status);
/*********************************************************************
* PROFILE CALLBACKS
*/
// GAP Role Callbacks
static gapRolesCBs_t AncsPeripheralCBs = {
AncsStateNotificationCB, // Profile State Change Callbacks
NULL, // When a valid RSSI is read from controller (not used by application)
AncsParamUpdateCB
};
// Bond Manager Callbacks
static gapBondCBs_t AncsBondCB = {
AncsPasscodeCB,
AncsPairStateCB
};
static struct bt_ancs_subscribe_cb *bt_ancs_subscribe;
void ancs_subscribe_cb_register(struct bt_ancs_subscribe_cb *cb)
{
bt_ancs_subscribe = cb;
}
/*********************************************************************
* @fn peripheral_ancs_client_init
*
* @brief Initialization function for the Central App Task.
* This is called during initialization and should contain
* any application specific initialization (ie. hardware
* initialization/setup, table initialization, power up
* notification).
*
* @param task_id - the ID assigned by TMOS. This ID should be
* used to send messages and set timers.
*
* @return none
*/
void peripheral_ancs_client_init(void)
{
ancs_taskid = TMOS_ProcessEventRegister(ANCS_ProcessEvent);
// Setup the GAP Peripheral Role Profile
{
uint8_t initial_advertising_enable = TRUE;
uint16_t desired_min_interval = DEFAULT_DESIRED_MIN_CONN_INTERVAL;
uint16_t desired_max_interval = DEFAULT_DESIRED_MAX_CONN_INTERVAL;
// Set the GAP Role Parameters
GAPRole_SetParameter(GAPROLE_ADVERT_ENABLED, sizeof(uint8_t), &initial_advertising_enable);
GAPRole_SetParameter(GAPROLE_SCAN_RSP_DATA, sizeof(scanRspData), scanRspData);
GAPRole_SetParameter(GAPROLE_ADVERT_DATA, sizeof(advertData), advertData);
GAPRole_SetParameter(GAPROLE_MIN_CONN_INTERVAL, sizeof(uint16_t), &desired_min_interval);
GAPRole_SetParameter(GAPROLE_MAX_CONN_INTERVAL, sizeof(uint16_t), &desired_max_interval);
}
// Set the GAP Characteristics
GGS_SetParameter(GGS_DEVICE_NAME_ATT, GAP_DEVICE_NAME_LEN, attDeviceName);
{
uint16_t advInt = DEFAULT_ADVERTISING_INTERVAL;
// Set advertising interval
GAP_SetParamValue(TGAP_DISC_ADV_INT_MIN, advInt);
GAP_SetParamValue(TGAP_DISC_ADV_INT_MAX, advInt);
// Enable scan req notify
GAP_SetParamValue(TGAP_ADV_SCAN_REQ_NOTIFY, ENABLE);
}
// Setup the GAP Bond Manager
{
uint32_t passkey = 0; // passkey "000000"
uint8_t pairMode = GAPBOND_PAIRING_MODE_WAIT_FOR_REQ;
uint8_t mitm = TRUE;
uint8_t bonding = TRUE;
uint8_t ioCap = GAPBOND_IO_CAP_DISPLAY_ONLY;
GAPBondMgr_SetParameter(GAPBOND_PERI_DEFAULT_PASSCODE, sizeof(uint32_t), &passkey);
GAPBondMgr_SetParameter(GAPBOND_PERI_PAIRING_MODE, sizeof(uint8_t), &pairMode);
GAPBondMgr_SetParameter(GAPBOND_PERI_MITM_PROTECTION, sizeof(uint8_t), &mitm);
GAPBondMgr_SetParameter(GAPBOND_PERI_IO_CAPABILITIES, sizeof(uint8_t), &ioCap);
GAPBondMgr_SetParameter(GAPBOND_PERI_BONDING_ENABLED, sizeof(uint8_t), &bonding);
}
// Initialize GATT Client
GATT_InitClient();
// Register to receive incoming ATT Indications/Notifications
GATT_RegisterForInd(ancs_taskid);
// Initialize GATT attributes
GGS_AddService(GATT_ALL_SERVICES); // GAP
GATTServApp_AddService(GATT_ALL_SERVICES); // GATT attributes
DevInfo_AddService();
// Setup a delayed profile startup
tmos_set_event(ancs_taskid, START_DEVICE_EVT);
}
/*********************************************************************
* @fn Central_ProcessEvent
*
* @brief Central 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 ANCS_ProcessEvent(uint8_t task_id, uint16_t events)
{
if(events & SYS_EVENT_MSG)
{
uint8_t *pMsg;
if((pMsg = tmos_msg_receive(ancs_taskid)) != NULL)
{
AncsProcessTMOSMsg((tmos_event_hdr_t *)pMsg);
// Release the TMOS message
tmos_msg_deallocate(pMsg);
}
// return unprocessed events
return (events ^ SYS_EVENT_MSG);
}
if(events & START_DEVICE_EVT)
{
// Start the Device
GAPRole_PeripheralStartDevice(ancs_taskid, &AncsBondCB, &AncsPeripheralCBs);
return (events ^ START_DEVICE_EVT);
}
if(events & START_SUBSCRIPE_NOTIDATA_EVT)
{
int err ;
if((err = bt_ancs_subscribe_data_source(&ancs_c,
bt_ancs_subscribe->data_source)) != SUCCESS){
if(err != -EALREADY)
tmos_start_task(ancs_taskid, START_SUBSCRIPE_NOTIDATA_EVT, MS1_TO_SYSTEM_TIME(100));
}
return (events ^ START_SUBSCRIPE_NOTIDATA_EVT);
}
if(events & START_SUBSCRIPE_NOTISRC_EVT)
{
int err ;
if((err = bt_ancs_subscribe_notification_source(&ancs_c,
bt_ancs_subscribe->notification_source)) != SUCCESS){
if(err != -EALREADY)
tmos_start_task(ancs_taskid, START_SUBSCRIPE_NOTISRC_EVT, MS1_TO_SYSTEM_TIME(100));
}
return (events ^ START_SUBSCRIPE_NOTISRC_EVT);
}
if(events & START_DISCOVER_EVT)
{
AncsApp_discoverService(NULL);
return (events ^ START_DISCOVER_EVT);
}
if(events & START_PARAM_UPDATE_EVT)
{
// start connect parameter update
GAPRole_PeripheralConnParamUpdateReq(ancs_conn_list.connHandle,
DEFAULT_UPDATE_MIN_CONN_INTERVAL,
DEFAULT_UPDATE_MAX_CONN_INTERVAL,
DEFAULT_UPDATE_SLAVE_LATENCY,
DEFAULT_UPDATE_CONN_TIMEOUT,
ancs_taskid);
return (events ^ START_PARAM_UPDATE_EVT);
}
if(events & START_PHY_UPDATE_EVT)
{
// start phy update
PRINT("PHY Update %x...\n", GAPRole_UpdatePHY(ancs_conn_list.connHandle, 0, GAP_PHY_BIT_LE_2M,
GAP_PHY_BIT_LE_2M, 0));
return (events ^ START_PHY_UPDATE_EVT);
}
// Discard unknown events
return 0;
}
/*********************************************************************
* @fn centralProcessGATTMsg
*
* @brief Process GATT messages
*
* @return none
*/
static void AncsProcessGATTMsg(gattMsgEvent_t *pMsg)
{
if(!atomic_test_bit(&ancs_c.state, ANCS_BT_CONNECTED)){
// In case a GATT message came after a connection has dropped,
// ignore the message
GATT_bm_free(&pMsg->msg, pMsg->method);
return;
}
if(!atomic_test_bit(&ancs_c.state, ANCS_BT_DISCOVERY_COMPLETE)){
AncsApp_discoverService(pMsg);
} else if (pMsg->method == ATT_HANDLE_VALUE_NOTI ||
pMsg->method == ATT_HANDLE_VALUE_IND) {
// Now in ancs_client.c
Ancs_handleNotification(pMsg);
} else if ((pMsg->method == ATT_READ_RSP) ||
((pMsg->method == ATT_ERROR_RSP) &&
(pMsg->msg.errorRsp.reqOpcode == ATT_READ_REQ))){
} else if((pMsg->method == ATT_WRITE_RSP) ||
((pMsg->method == ATT_ERROR_RSP) &&
(pMsg->msg.errorRsp.reqOpcode == ATT_WRITE_REQ))){
bt_ancs_write_cb write_cb;
write_cb = ancs_c.cp_write_cb;
atomic_clear_bit(&ancs_c.state, ANCS_CP_WRITE_PENDING);
if (write_cb) {
write_cb(&ancs_c, pMsg->msg.errorRsp.errCode);
}
} else if(pMsg->method == ATT_ERROR_RSP){
PRINT("response %#x error: %#x\n", pMsg->msg.errorRsp.reqOpcode,
pMsg->msg.errorRsp.errCode);
}
GATT_bm_free(&pMsg->msg, pMsg->method);
}
/*********************************************************************
* @fn central_ProcessTMOSMsg
*
* @brief Process an incoming task message.
*
* @param pMsg - message to process
*
* @return none
*/
static void AncsProcessTMOSMsg(tmos_event_hdr_t *pMsg)
{
switch(pMsg->event)
{
case GATT_MSG_EVENT:
AncsProcessGATTMsg((gattMsgEvent_t *)pMsg);
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(ancs_conn_list.connHandle != GAP_CONNHANDLE_INIT)
{
GAPRole_TerminateLink(pEvent->linkCmpl.connectionHandle);
PRINT("Connection max...\n");
}
else
{
ancs_conn_list.connHandle = event->connectionHandle;
ancs_conn_list.connInterval = event->connInterval;
ancs_conn_list.connSlaveLatency = event->connLatency;
ancs_conn_list.connTimeout = event->connTimeout;
ancs_c.conn = ancs_conn_list.connHandle;
atomic_set_bit(&ancs_c.state, ANCS_BT_CONNECTED);
// Set timer for param update event
tmos_start_task(ancs_taskid, START_PARAM_UPDATE_EVT, DEFAULT_PARAM_UPDATE_DELAY);
discoveryState = DISC_ANCS_START;
PRINT("Conn: %d - params: %d %d %d\n", event->connectionHandle,
event->connInterval, event->connLatency, event->connTimeout);
}
}
/*********************************************************************
* @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 == ancs_conn_list.connHandle)
{
ancs_conn_list.connHandle = GAP_CONNHANDLE_INIT;
ancs_conn_list.connInterval = 0;
ancs_conn_list.connSlaveLatency = 0;
ancs_conn_list.connTimeout = 0;
// Restart advertising
{
uint8_t advertising_enable = TRUE;
GAPRole_SetParameter(GAPROLE_ADVERT_ENABLED, sizeof(uint8_t), &advertising_enable);
}
ancs_reinit(&ancs_c);
}
else
{
PRINT("ERR..\n");
}
}
static void AncsParamUpdateCB(uint16_t connHandle, uint16_t connInterval,
uint16_t connSlaveLatency, uint16_t connTimeout)
{
if(connHandle == ancs_conn_list.connHandle)
{
ancs_conn_list.connInterval = connInterval;
ancs_conn_list.connSlaveLatency = connSlaveLatency;
ancs_conn_list.connTimeout = connTimeout;
PRINT("update: %d - params: %d %d %d\n", connHandle,
connInterval, connSlaveLatency, connTimeout);
}
else
{
PRINT("ERR..\n");
}
}
static void AncsStateNotificationCB(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("Disconnected.. Reason:%x\n", pEvent->linkTerminate.reason);
PRINT("Advertising..\n");
}
else if(pEvent->gap.opcode == GAP_MAKE_DISCOVERABLE_DONE_EVENT)
{
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:
if(pEvent->gap.opcode == GAP_MAKE_DISCOVERABLE_DONE_EVENT)
{
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;
}
}
/*********************************************************************
* @fn pairStateCB
*
* @brief Pairing state callback.
*
* @return none
*/
static void AncsPairStateCB(uint16_t connHandle, uint8_t state, uint8_t status)
{
if(state == GAPBOND_PAIRING_STATE_STARTED)
{
PRINT("Pairing started:%d\n", status);
}
else if(state == GAPBOND_PAIRING_STATE_COMPLETE)
{
if(status == SUCCESS)
{
PRINT("Pairing success\n");
}
else
{
PRINT("Pairing fail\n");
}
}
else if(state == GAPBOND_PAIRING_STATE_BONDED)
{
if(status == SUCCESS)
{
PRINT("Bonding success\n");
tmos_set_event(ancs_taskid, START_DISCOVER_EVT);
}
}
else if(state == GAPBOND_PAIRING_STATE_BOND_SAVED)
{
if(status == SUCCESS)
{
PRINT("Bond save success\n");
tmos_set_event(ancs_taskid, START_DISCOVER_EVT);
}
else
{
PRINT("Bond save failed: %d\n", status);
}
}
}
/*********************************************************************
* @fn centralPasscodeCB
*
* @brief Passcode callback.
*
* @return none
*/
static void AncsPasscodeCB(uint8_t *deviceAddr, uint16_t connectionHandle,
uint8_t uiInputs, uint8_t uiOutputs)
{
uint32_t passcode;
// Create random passcode
passcode = tmos_rand();
passcode %= 1000000;
// Display passcode to user
if(uiOutputs != 0)
{
PRINT("Passcode:%06d\n", (int)passcode);
}
// Send passcode response
GAPBondMgr_PasscodeRsp(connectionHandle, SUCCESS, passcode);
}
/*********************************************************************
* @fn centralGATTDiscoveryEvent
*
* @brief Process GATT discovery event
*
* @return none
*/
static void AncsApp_discoverService(gattMsgEvent_t *pMsg)
{
static uint16_t Ancs_svcStartHdl;
static uint16_t Ancs_svcEndHdl;
static uint8_t Ancs_endHdlIdx;
static uint8_t isNotifCCCD = FALSE;
switch (discoveryState)
{
case DISC_ANCS_START:
{
uint8_t uuid[ATT_UUID_SIZE] = {ANCS_SVC_UUID};
// Initialize service discovery variables
Ancs_svcStartHdl = Ancs_svcEndHdl = 0;
Ancs_endHdlIdx = 0;
// Discover ANCS service by UUID
GATT_DiscPrimaryServiceByUUID(ancs_c.conn, uuid,
ATT_UUID_SIZE, ancs_taskid);
discoveryState = DISC_ANCS_SVC;
}
break;
case DISC_ANCS_SVC:
// Service found, store handles
if (pMsg->method == ATT_FIND_BY_TYPE_VALUE_RSP &&
pMsg->msg.findByTypeValueRsp.numInfo > 0)
{
Ancs_svcStartHdl =
ATT_ATTR_HANDLE(pMsg->msg.findByTypeValueRsp.pHandlesInfo, 0);
Ancs_svcEndHdl =
ATT_GRP_END_HANDLE(pMsg->msg.findByTypeValueRsp.pHandlesInfo, 0);
}
// If procedure complete
if ((pMsg->method == ATT_FIND_BY_TYPE_VALUE_RSP &&
pMsg->hdr.status == bleProcedureComplete) ||
(pMsg->method == ATT_ERROR_RSP))
{
// If service found
if (Ancs_svcStartHdl != 0)
{
// Discover all characteristics
GATT_DiscAllChars(pMsg->connHandle, Ancs_svcStartHdl,
Ancs_svcEndHdl, ancs_taskid);
discoveryState = DISC_ANCS_CHAR;
}
else
{
// Service not found
discoveryState = DISC_FAILED;
PRINT("ANCS SVC not present\n");
}
}
break;
case DISC_ANCS_CHAR:
{
// Characteristics found, chache them
uint8_t *pHandleValuePairList;
uint16_t handle;
uint16_t uuid;
if (pMsg->method == ATT_READ_BY_TYPE_RSP &&
pMsg->msg.readByTypeRsp.numPairs > 0 &&
pMsg->msg.readByTypeRsp.len == CHAR_DESC_HDL_UUID128_LEN)
{
pHandleValuePairList = pMsg->msg.readByTypeRsp.pDataList;
uint8_t i;
// For each handle value pair in the list of chars in ANCS service
for (i = pMsg->msg.readByTypeRsp.numPairs; i > 0; i--)
{
// Parse characteristic declaration
handle = BUILD_UINT16(pHandleValuePairList[3],
pHandleValuePairList[4]);
uuid = BUILD_UINT16(pHandleValuePairList[5],
pHandleValuePairList[6]);
// If looking for end handle
if (Ancs_endHdlIdx != 0)
{
// End handle is characteristic declaration handle - 1
Ancs_handleCache[Ancs_endHdlIdx] =
BUILD_UINT16(pHandleValuePairList[0],
pHandleValuePairList[1]) - 1;
Ancs_endHdlIdx = 0;
}
// If UUID is of interest, cache handle
switch (uuid)
{
case ANCS_NOTIF_SRC_CHAR_UUID:
ancs_c.handle_ns = handle;
Ancs_handleCache[HDL_ANCS_NTF_NOTIF_START] = handle;
Ancs_endHdlIdx = HDL_ANCS_NTF_NOTIF_END;
break;
case ANCS_CTRL_PT_CHAR_UUID:
ancs_c.handle_cp = handle;
Ancs_handleCache[HDL_ANCS_CTRL_PT_START] = handle;
Ancs_endHdlIdx = HDL_ANCS_CTRL_PT_END;
break;
case ANCS_DATA_SRC_CHAR_UUID:
ancs_c.handle_ds = handle;
Ancs_handleCache[HDL_ANCS_DATA_SRC_START] = handle;
Ancs_endHdlIdx = HDL_ANCS_DATA_SRC_END;
break;
default:
break;
}
pHandleValuePairList += CHAR_DESC_HDL_UUID128_LEN;
}
}
// If procedure complete
if ((pMsg->method == ATT_READ_BY_TYPE_RSP &&
pMsg->hdr.status == bleProcedureComplete) ||
(pMsg->method == ATT_ERROR_RSP))
{
// Special case of end handle at end of service
if (Ancs_endHdlIdx != 0)
{
Ancs_handleCache[Ancs_endHdlIdx] = Ancs_svcEndHdl;
Ancs_endHdlIdx = 0;
}
// If notification source char is missing, there is something wrong
if (Ancs_handleCache[HDL_ANCS_NTF_NOTIF_START] == 0)
{
PRINT("Notif src not found\n");
discoveryState = DISC_FAILED;
}
else if (Ancs_handleCache[HDL_ANCS_NTF_NOTIF_START] <
Ancs_handleCache[HDL_ANCS_NTF_NOTIF_END])
{
// Discover ANCS Notification Source CCCD
GATT_DiscAllCharDescs(pMsg->connHandle,
Ancs_handleCache[HDL_ANCS_NTF_NOTIF_START] + 1,
Ancs_handleCache[HDL_ANCS_NTF_NOTIF_END],
ancs_taskid);
isNotifCCCD = TRUE;
discoveryState = DISC_ANCS_CCCD;
}
else
{
PRINT("CCCD missing\n");
// Missing required characteristic descriptor
Ancs_handleCache[HDL_ANCS_NTF_NOTIF_START] = 0;
discoveryState = DISC_FAILED;
}
}
// Discover all characteristics of ANCS service until end handle
else
{
GATT_DiscAllChars(pMsg->connHandle, handle+1,
Ancs_svcEndHdl, ancs_taskid);
}
}
break;
case DISC_ANCS_CCCD:
{
// Characteristic descriptors found
if (pMsg->method == ATT_FIND_INFO_RSP &&
pMsg->msg.findInfoRsp.numInfo > 0 &&
pMsg->msg.findInfoRsp.format == 0x01)
{
uint8_t i;
// For each handle/uuid pair
for (i = 0; i < pMsg->msg.findInfoRsp.numInfo; i++)
{
// Look for CCCD
if (ATT_BT_PAIR_UUID(pMsg->msg.findInfoRsp.pInfo, i) ==
GATT_CLIENT_CHAR_CFG_UUID)
{
// CCCD found
// if it is Notification Source CCCD
if (isNotifCCCD == TRUE)
{
ancs_c.handle_ns_ccc =
ATT_BT_PAIR_HANDLE(pMsg->msg.findInfoRsp.pInfo, i);
Ancs_handleCache[HDL_ANCS_NTF_CCCD] =
ATT_BT_PAIR_HANDLE(pMsg->msg.findInfoRsp.pInfo, i);
}
// else it is Data Source CCCD
else
{
ancs_c.handle_ds_ccc =
ATT_BT_PAIR_HANDLE(pMsg->msg.findInfoRsp.pInfo, i);
Ancs_handleCache[HDL_ANCS_DATA_SRC_CCCD] =
ATT_BT_PAIR_HANDLE(pMsg->msg.findInfoRsp.pInfo, i);
}
break;
}
}
}
// If procedure complete
if ((pMsg->method == ATT_FIND_INFO_RSP &&
pMsg->hdr.status == bleProcedureComplete) ||
(pMsg->method == ATT_ERROR_RSP))
{
// Discover ANCS Data Source characteristic descriptors
if (isNotifCCCD == TRUE &&
Ancs_handleCache[HDL_ANCS_DATA_SRC_CCCD] == 0)
{
GATT_DiscAllCharDescs(pMsg->connHandle,
Ancs_handleCache[HDL_ANCS_DATA_SRC_START] + 1,
Ancs_handleCache[HDL_ANCS_DATA_SRC_END],
ancs_taskid);
isNotifCCCD = FALSE;
}
else
{
discoveryState = DISC_IDLE;
atomic_set_bit(&ancs_c.state, ANCS_BT_DISCOVERY_COMPLETE);
PRINT("discover complete\n");
tmos_set_event(ancs_taskid, START_SUBSCRIPE_NOTIDATA_EVT);
tmos_set_event(ancs_taskid, START_SUBSCRIPE_NOTISRC_EVT);
}
}
}
break;
default:
break;
}
}
/************************ endfile @ central **************************/
@@ -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,135 @@
/*
* 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 ANCS_H
#define ANCS_H
#ifdef __cplusplus
extern "C"
{
#endif
/*********************************************************************
* INCLUDES
*/
#include "config.h"
#include "ancs_client.h"
#include <stdint.h>
/*********************************************************************
* CONSTANTS
*/
// ANCS discovery states
enum
{
DISC_IDLE = 0x00, // Idle state
DISC_ANCS_START = 0x10, // ANCS service
DISC_ANCS_SVC, // Discover service
DISC_ANCS_CHAR, // Discover all characteristics
DISC_ANCS_CCCD, // Discover ANCS CCCD
DISC_FAILED = 0xFF // Discovery failed
};
// ANCS handle cache indexes
enum
{
HDL_ANCS_NTF_NOTIF_START, // ANCS notification characteristic start handle
HDL_ANCS_NTF_NOTIF_END, // ANCS notification characteristic end handle
HDL_ANCS_NTF_CCCD, // ANCS notification CCCD
HDL_ANCS_CTRL_PT_START,
HDL_ANCS_CTRL_PT_END,
HDL_ANCS_DATA_SRC_START, // ANCS data source characteristic start handle
HDL_ANCS_DATA_SRC_END, // ANCS data source characteristic end handle
HDL_ANCS_DATA_SRC_CCCD, // ANCS data source CCCD
HDL_CACHE_LEN
};
/*********************************************************************
* TYPEDEFS
*/
struct bt_ancs_subscribe_cb {
void(*notification_source)(struct bt_ancs_client *ancs_c,
int err, const struct bt_ancs_evt_notif *notif);
void(*data_source)(struct bt_ancs_client *ancs_c,
const struct bt_ancs_attr_response *response);
void(*write_response)(struct bt_ancs_client *ancs_c,
uint8_t err);
};
typedef struct
{
uint16_t connHandle; // Connection handle of current connection
uint16_t connInterval;
uint16_t connSlaveLatency;
uint16_t connTimeout;
} peripheralConnItem_t;
/*********************************************************************
* MACROS
*/
#define START_DEVICE_EVT 0x0001
#define START_SUBSCRIPE_NOTISRC_EVT 0x0002
#define START_SUBSCRIPE_NOTIDATA_EVT 0x0004
#define START_DISCOVER_EVT 0x0008
#define START_PARAM_UPDATE_EVT 0x0010
#define START_PHY_UPDATE_EVT 0x0020
// Handle and 16-bit Bluetooth UUID pair indexes
#define ATT_BT_PAIR_HANDLE_IDX( i ) ( (i) * (2 + ATT_BT_UUID_SIZE) )
#define ATT_BT_PAIR_UUID_IDX( i ) ( ATT_BT_PAIR_HANDLE_IDX( (i) ) + 2 )
#define ATT_BT_PAIR_HANDLE( info, i ) ( BUILD_UINT16( (info)[ATT_BT_PAIR_HANDLE_IDX((i))], \
(info)[ATT_BT_PAIR_HANDLE_IDX((i))+1] ) )
#define ATT_BT_PAIR_UUID( info, i ) ( BUILD_UINT16( (info)[ATT_BT_PAIR_UUID_IDX((i))], \
(info)[ATT_BT_PAIR_UUID_IDX((i))+1] ) )
/*********************************************************************
* GLOBAL
*/
enum
{
CCCD_CONFIG_NOTIF = 0x00,
CCCD_CONFIG_DATA,
CCCD_CONFIG_DONE
};
extern struct bt_ancs_client ancs_c;
extern uint8_t ancs_taskid;
// Handle cache
extern uint16_t Ancs_handleCache[HDL_CACHE_LEN];
/*********************************************************************
* FUNCTIONS
*/
/*
* ANCS service discovery functions.
*/
void peripheral_ancs_client_init(void);
void ancs_subscribe_cb_register(struct bt_ancs_subscribe_cb *cb);
/*********************************************************************
*********************************************************************/
#ifdef __cplusplus
}
#endif
#endif /* ANCS_H */
@@ -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,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 */
@@ -0,0 +1,32 @@
#ifndef TIME_UNITS_H
#define TIME_UNITS_H
#include "config.h"
#ifdef CLK_OSC32K
#if (CLK_OSC32K==1)
#define FREQ_RTC 32000
#else
#define FREQ_RTC 32768
#endif
#endif /* CLK_OSC32K */
#define CLK_PER_US (1.0 / ((1.0 / FREQ_RTC) * 1000 * 1000)) // 0.032 clk/us
#define CLK_PER_MS (CLK_PER_US * 1000) // 32clk/ms
#define US_PER_CLK (1.0 / CLK_PER_US) // 31.25us/clk
#define MS_PER_CLK (US_PER_CLK / 1000.0) // 0.03125ms/clk
#define SYS_TO_US(clk) ((uint32_t)((clk) * US_PER_CLK))
#define SYS_TO_MS(clk) ((uint32_t)((clk) * MS_PER_CLK))
#define US_TO_SYS(us) ((uint32_t)((us) * CLK_PER_US))
#define MS_TO_SYS(ms) ((uint32_t)((ms) * CLK_PER_MS ))
static inline uint32_t get_current_time(void)
{
return SYS_TO_MS(RTC_GetCounter());
}
#endif /* TIME_UNITS_H */
@@ -0,0 +1,413 @@
/********************************** (C) COPYRIGHT *******************************
* File Name : main.c
* Author : WCH
* Version : V1.1
* Date : 2020/08/06
* 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 <time_units.h>
#include "CONFIG.h"
#include "HAL.h"
#include "ancs.h"
#include "ancs_client.h"
#include "time_units.h"
static void bt_ancs_notification_source_handler(struct bt_ancs_client *ancs_c,
int err, const struct bt_ancs_evt_notif *notif);
static void bt_ancs_data_source_handler(struct bt_ancs_client *ancs_c,
const struct bt_ancs_attr_response *response);
static void bt_ancs_write_response_handler(struct bt_ancs_client *ancs_c,
uint8_t err);
__attribute__((aligned(4))) uint32_t MEM_BUF[BLE_MEMHEAP_SIZE / 4];
#if(defined(BLE_MAC)) && (BLE_MAC == TRUE)
const uint8_t MacAddr[6] = {0x84, 0xC2, 0xE4, 0x03, 0x02, 0x02};
#endif
#define ATTR_DATA_SIZE BT_ANCS_ATTR_DATA_MAX
#define KEY_REQ_NOTI_ATTR (1<<0)
#define KEY_REQ_APP_ATTR (1<<1)
#define KEY_POS_ACTION (1<<0)
#define KEY_NEG_ACTION (1<<0)
static struct bt_ancs_subscribe_cb subscribe = {
.data_source = bt_ancs_data_source_handler,
.notification_source = bt_ancs_notification_source_handler,
.write_response = bt_ancs_write_response_handler,
};
/* Local copy to keep track of the newest arriving notifications. */
static struct bt_ancs_evt_notif notification_latest;
/* Local copy of the newest notification attribute. */
static struct bt_ancs_attr notif_attr_latest;
/* Local copy of the newest app attribute. */
static struct bt_ancs_attr notif_attr_app_id_latest;
/* Buffers to store attribute data. */
static uint8_t attr_appid[ATTR_DATA_SIZE];
static uint8_t attr_title[ATTR_DATA_SIZE];
static uint8_t attr_subtitle[ATTR_DATA_SIZE];
static uint8_t attr_message[ATTR_DATA_SIZE];
static uint8_t attr_message_size[ATTR_DATA_SIZE];
static uint8_t attr_date[ATTR_DATA_SIZE];
static uint8_t attr_posaction[ATTR_DATA_SIZE];
static uint8_t attr_negaction[ATTR_DATA_SIZE];
static uint8_t attr_disp_name[ATTR_DATA_SIZE];
/* String literals for the iOS notification categories.
* Used then printing to UART.
*/
static const char *lit_catid[BT_ANCS_CATEGORY_ID_COUNT] = {
"Other",
"Incoming Call",
"Missed Call",
"Voice Mail",
"Social",
"Schedule",
"Email",
"News",
"Health And Fitness",
"Business And Finance",
"Location",
"Entertainment"
};
/* String literals for the iOS notification event types.
* Used then printing to UART.
*/
static const char *lit_eventid[BT_ANCS_EVT_ID_COUNT] = { "Added",
"Modified",
"Removed" };
/* String literals for the iOS notification attribute types.
* Used when printing to UART.
*/
static const char *lit_attrid[BT_ANCS_NOTIF_ATTR_COUNT] = {
"App Identifier",
"Title",
"Subtitle",
"Message",
"Message Size",
"Date",
"Positive Action Label",
"Negative Action Label"
};
static const char *lit_appid[BT_ANCS_APP_ATTR_COUNT] = { "Display Name" };
static void notif_print(struct bt_ancs_evt_notif *notif)
{
PRINT("\nNotification\n");
PRINT("Event: %s\n", lit_eventid[notif->evt_id]);
PRINT("Category ID: %s\n", lit_catid[notif->category_id]);
PRINT("Category Cnt:%u\n", (unsigned int)notif->category_count);
PRINT("UID: %u\n", (unsigned int)notif->notif_uid);
PRINT("Flags:\n");
if (notif->evt_flags.silent) {
PRINT(" Silent\n");
}
if (notif->evt_flags.important) {
PRINT(" Important\n");
}
if (notif->evt_flags.pre_existing) {
PRINT(" Pre-existing\n");
}
if (notif->evt_flags.positive_action) {
PRINT(" Positive Action\n");
}
if (notif->evt_flags.negative_action) {
PRINT(" Negative Action\n");
}
}
/**@brief Function for printing iOS notification attribute data.
*
* @param[in] attr Pointer to an iOS notification attribute.
*/
static void notif_attr_print(const struct bt_ancs_attr *attr)
{
if (attr->attr_len != 0) {
PRINT("%s: %s\n", lit_attrid[attr->attr_id],
(char *)attr->attr_data);
} else if (attr->attr_len == 0) {
PRINT("%s: (N/A)\n", lit_attrid[attr->attr_id]);
}
}
/**@brief Function for printing iOS notification attribute data.
*
* @param[in] attr Pointer to an iOS App attribute.
*/
static void app_attr_print(const struct bt_ancs_attr *attr)
{
if (attr->attr_len != 0) {
PRINT("%s: %s\n", lit_appid[attr->attr_id],
(char *)attr->attr_data);
} else if (attr->attr_len == 0) {
PRINT("%s: (N/A)\n", lit_appid[attr->attr_id]);
}
}
static int ancs_init(void)
{
int err;
err = bt_ancs_client_init(&ancs_c);
if (err) {
return err;
}
err = bt_ancs_register_attr(&ancs_c,
BT_ANCS_NOTIF_ATTR_ID_APP_IDENTIFIER,
attr_appid, ATTR_DATA_SIZE);
if (err) {
return err;
}
err = bt_ancs_register_app_attr(&ancs_c,
BT_ANCS_APP_ATTR_ID_DISPLAY_NAME,
attr_disp_name, sizeof(attr_disp_name));
if (err) {
return err;
}
err = bt_ancs_register_attr(&ancs_c,
BT_ANCS_NOTIF_ATTR_ID_TITLE,
attr_title, ATTR_DATA_SIZE);
if (err) {
return err;
}
err = bt_ancs_register_attr(&ancs_c,
BT_ANCS_NOTIF_ATTR_ID_MESSAGE,
attr_message, ATTR_DATA_SIZE);
if (err) {
return err;
}
err = bt_ancs_register_attr(&ancs_c,
BT_ANCS_NOTIF_ATTR_ID_SUBTITLE,
attr_subtitle, ATTR_DATA_SIZE);
if (err) {
return err;
}
err = bt_ancs_register_attr(&ancs_c,
BT_ANCS_NOTIF_ATTR_ID_MESSAGE_SIZE,
attr_message_size, ATTR_DATA_SIZE);
if (err) {
return err;
}
err = bt_ancs_register_attr(&ancs_c,
BT_ANCS_NOTIF_ATTR_ID_DATE,
attr_date, ATTR_DATA_SIZE);
if (err) {
return err;
}
err = bt_ancs_register_attr(&ancs_c,
BT_ANCS_NOTIF_ATTR_ID_POSITIVE_ACTION_LABEL,
attr_posaction, ATTR_DATA_SIZE);
if (err) {
return err;
}
err = bt_ancs_register_attr(&ancs_c,
BT_ANCS_NOTIF_ATTR_ID_NEGATIVE_ACTION_LABEL,
attr_negaction, ATTR_DATA_SIZE);
return err;
}
static void bt_ancs_notification_source_handler(struct bt_ancs_client *ancs_c,
int err, const struct bt_ancs_evt_notif *notif)
{
if (!err) {
notification_latest = *notif;
notif_print(&notification_latest);
}
}
static void bt_ancs_data_source_handler(struct bt_ancs_client *ancs_c,
const struct bt_ancs_attr_response *response)
{
switch (response->command_id) {
case BT_ANCS_COMMAND_ID_GET_NOTIF_ATTRIBUTES:
notif_attr_latest = response->attr;
notif_attr_print(&notif_attr_latest);
if (response->attr.attr_id ==
BT_ANCS_NOTIF_ATTR_ID_APP_IDENTIFIER) {
notif_attr_app_id_latest = response->attr;
}
break;
case BT_ANCS_COMMAND_ID_GET_APP_ATTRIBUTES:
app_attr_print(&response->attr);
break;
default:
/* No implementation needed. */
break;
}
}
static void bt_ancs_write_response_handler(struct bt_ancs_client *ancs_c,
uint8_t err)
{
switch (err) {
case BT_ATT_ERR_ANCS_NP_UNKNOWN_COMMAND:
PRINT("Error: Command ID was not recognized by the Notification Provider.\n");
break;
case BT_ATT_ERR_ANCS_NP_INVALID_COMMAND:
PRINT("Error: Command failed to be parsed on the Notification Provider.\n");
break;
case BT_ATT_ERR_ANCS_NP_INVALID_PARAMETER:
PRINT("Error: Parameter does not refer to an existing object on the Notification Provider.\n");
break;
case BT_ATT_ERR_ANCS_NP_ACTION_FAILED:
PRINT("Error: Perform Notification Action Failed on the Notification Provider.\n");
break;
default:
break;
}
}
struct key_state {
uint32_t timestamp_key1;
uint32_t timestamp_key2;
};
/**
* key1(PB22):
* single: request attributes for a notification.
* double: request attributes for a given app.
*
* key2(PB4):
* single: perform a positive action.
* double: perform a negative action.
*/
void button_changed(uint8_t keys)
{
int err;
static struct key_state k_s = {0};
if(keys & HAL_KEY_SW_1){
uint32_t current_time = get_current_time();
if(current_time - k_s.timestamp_key1 < 600){
if (notif_attr_app_id_latest.attr_id ==
BT_ANCS_NOTIF_ATTR_ID_APP_IDENTIFIER &&
notif_attr_app_id_latest.attr_len != 0) {
PRINT("Request for %s:\n",
notif_attr_app_id_latest.attr_data);
err = bt_ancs_request_app_attr(
&ancs_c, notif_attr_app_id_latest.attr_data,
notif_attr_app_id_latest.attr_len,
bt_ancs_write_response_handler);
if (err) {
PRINT("Failed requesting attributes for a given app (err: %d)\n",
err);
}
}
} else {
err = bt_ancs_request_attrs(&ancs_c, &notification_latest,
bt_ancs_write_response_handler);
if(err){
PRINT("Failed requesting attributes for a notification (err: %d)\n",
err);
}
}
k_s.timestamp_key1 = current_time;
}
if(keys & HAL_KEY_SW_2){
uint32_t current_time = get_current_time();
if(current_time - k_s.timestamp_key2 < 600){
PRINT("Performing Negative Action.\n");
err = bt_ancs_notification_action(
&ancs_c, notification_latest.notif_uid,
BT_ANCS_ACTION_ID_NEGATIVE,
bt_ancs_write_response_handler);
if (err) {
PRINT("Failed performing action (err: %d)\n",
err);
}
} else {
PRINT("Performing Positive Action.\n");
err = bt_ancs_notification_action(
&ancs_c, notification_latest.notif_uid,
BT_ANCS_ACTION_ID_POSITIVE,
bt_ancs_write_response_handler);
if (err) {
PRINT("Failed performing action (err: %d)\n",
err);
}
}
k_s.timestamp_key2 = current_time;
}
}
/*********************************************************************
* @fn Main_Circulation
*
* @brief Main loop
*
* @return none
*/
__attribute__((section(".highcode")))
__attribute__((noinline))
void Main_Circulation(void)
{
while(1)
{
TMOS_SystemProcess();
}
}
/*********************************************************************
* @fn main
*
* @brief Main function
*
* @return none
*/
int main(void)
{
Delay_Init();
#ifdef DEBUG
USART_Printf_Init( 115200 );
#endif
PRINT("start.%s\n",__TIME__);
PRINT("%s\n", VER_LIB);
WCHBLE_Init();
HAL_Init();
HalKeyConfig(button_changed);
ancs_init();
ancs_subscribe_cb_register(&subscribe);
GAPRole_PeripheralInit();
peripheral_ancs_client_init();
Main_Circulation();
}
/******************************** endfile @ main ******************************/
@@ -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