feat: ble: add battery level characteristic (#66)
App might read battery level from characteristic/service uuid: 0x2A19/0x180F
This commit is contained in:
committed by
GitHub
parent
03e30b4b24
commit
512134607b
2
Makefile
2
Makefile
@@ -64,6 +64,7 @@ src/leddrv.c \
|
||||
src/button.c \
|
||||
src/bmlist.c \
|
||||
src/ble/profile/legacy.c \
|
||||
src/ble/profile/batt.c \
|
||||
src/ble/profile/devinfo.c \
|
||||
src/ble/setup.c \
|
||||
src/ble/peripheral.c \
|
||||
@@ -79,6 +80,7 @@ src/xbm.c \
|
||||
src/resource.c \
|
||||
src/animation.c \
|
||||
src/font.c \
|
||||
src/power.c \
|
||||
|
||||
|
||||
# ASM sources
|
||||
|
||||
@@ -3,5 +3,6 @@
|
||||
|
||||
int legacy_registerService();
|
||||
int devInfo_registerService();
|
||||
int batt_registerService();
|
||||
|
||||
#endif /* __BLE_UART_SERVICE_H__ */
|
||||
|
||||
52
src/ble/profile/batt.c
Normal file
52
src/ble/profile/batt.c
Normal file
@@ -0,0 +1,52 @@
|
||||
#include "utils.h"
|
||||
|
||||
#include "../../power.h"
|
||||
|
||||
static const uint16_t ServiceUUID = 0x180F;
|
||||
static const gattAttrType_t service = {2, (uint8_t *)&ServiceUUID};
|
||||
|
||||
static const uint16_t battLv_CharUUID = 0x2A19;
|
||||
static uint8 battLv_CharProps = GATT_PROP_READ;
|
||||
static uint8 battLv_Val[1];
|
||||
|
||||
static gattAttribute_t attr_table[] = {
|
||||
ATTR_DECLAR(primaryServiceUUID, 2, GATT_PERMIT_READ, &service),
|
||||
|
||||
CHAR_DECLAR(&battLv_CharProps),
|
||||
CHAR_VAL_DECLAR(&battLv_CharUUID, 2, GATT_PERMIT_READ, battLv_Val),
|
||||
};
|
||||
|
||||
static bStatus_t read_handler(uint16_t connHandle, gattAttribute_t *pAttr,
|
||||
uint8_t *p_value, uint16_t *pLen, uint16_t offset,
|
||||
uint16_t maxLen, uint8_t method)
|
||||
{
|
||||
uint16_t uuid = BUILD_UINT16(pAttr->type.uuid[0], pAttr->type.uuid[1]);
|
||||
|
||||
if (uuid != battLv_CharUUID) {
|
||||
*pLen = 0;
|
||||
return ATT_ERR_ATTR_NOT_FOUND;
|
||||
}
|
||||
|
||||
*pLen = 1;
|
||||
battLv_Val[0] = batt_raw2percent(batt_raw());
|
||||
tmos_memcpy(p_value, battLv_Val, *pLen);
|
||||
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
static gattServiceCBs_t service_handlers = {
|
||||
read_handler,
|
||||
NULL,
|
||||
NULL
|
||||
};
|
||||
|
||||
int batt_registerService()
|
||||
{
|
||||
uint8 status = SUCCESS;
|
||||
|
||||
status = GATTServApp_RegisterService(attr_table,
|
||||
GATT_NUM_ATTRS(attr_table),
|
||||
GATT_MAX_ENCRYPT_KEY_SIZE,
|
||||
&service_handlers);
|
||||
return (status);
|
||||
}
|
||||
@@ -65,7 +65,7 @@ static bStatus_t write_handler(uint16 connHandle, gattAttribute_t *pAttr,
|
||||
return ATT_ERR_ATTR_NOT_FOUND;
|
||||
}
|
||||
|
||||
gattServiceCBs_t service_handlers = {
|
||||
static gattServiceCBs_t service_handlers = {
|
||||
NULL,
|
||||
write_handler,
|
||||
NULL
|
||||
|
||||
81
src/main.c
81
src/main.c
@@ -49,8 +49,6 @@ enum MODES {
|
||||
#define SCAN_BOOTLD_BTN (1 << 3)
|
||||
#define BLE_NEXT_STEP (1 << 4)
|
||||
|
||||
#define CHARGE_STT_PIN GPIO_Pin_0 // PA0
|
||||
|
||||
static tmosTaskID common_taskid = INVALID_TASK_ID ;
|
||||
|
||||
volatile uint16_t fb[LED_COLS] = {0};
|
||||
@@ -108,24 +106,6 @@ void load_bmlist()
|
||||
bmlist_drop(curr_bm);
|
||||
}
|
||||
|
||||
void poweroff()
|
||||
{
|
||||
// Stop wasting energy
|
||||
GPIOA_ModeCfg(GPIO_Pin_All, GPIO_ModeIN_Floating);
|
||||
GPIOB_ModeCfg(GPIO_Pin_All, GPIO_ModeIN_Floating);
|
||||
|
||||
// Configure wake-up
|
||||
GPIOA_ModeCfg(KEY1_PIN, GPIO_ModeIN_PD);
|
||||
GPIOA_ITModeCfg(KEY1_PIN, GPIO_ITMode_RiseEdge);
|
||||
GPIOA_ModeCfg(CHARGE_STT_PIN, GPIO_ModeIN_PU);
|
||||
GPIOA_ITModeCfg(CHARGE_STT_PIN, GPIO_ITMode_FallEdge);
|
||||
PFIC_EnableIRQ(GPIO_A_IRQn);
|
||||
PWR_PeriphWakeUpCfg(ENABLE, RB_SLP_GPIO_WAKE, Long_Delay);
|
||||
|
||||
/* Good bye */
|
||||
LowPower_Shutdown(0);
|
||||
}
|
||||
|
||||
static uint16_t common_tasks(tmosTaskID task_id, uint16_t events)
|
||||
{
|
||||
static int marque_step, flash_step;
|
||||
@@ -229,6 +209,7 @@ void ble_setup()
|
||||
|
||||
devInfo_registerService();
|
||||
legacy_registerService();
|
||||
batt_registerService();
|
||||
}
|
||||
|
||||
static void usb_receive(uint8_t *buf, uint16_t len)
|
||||
@@ -328,37 +309,6 @@ static void debug_init()
|
||||
UART1_BaudRateCfg(921600);
|
||||
}
|
||||
|
||||
uint16_t adcBuff[40];
|
||||
static int read_batt_raw()
|
||||
{
|
||||
int ret = 0;
|
||||
/* adc 1 - pa5 */
|
||||
PRINT("\n2.Single channel sampling...\n");
|
||||
GPIOA_ModeCfg(GPIO_Pin_5, GPIO_ModeIN_Floating);
|
||||
ADC_ExtSingleChSampInit(SampleFreq_3_2, ADC_PGA_0);
|
||||
|
||||
int16_t RoughCalib_Value = ADC_DataCalib_Rough();
|
||||
PRINT("RoughCalib_Value =%d \n", RoughCalib_Value);
|
||||
|
||||
ADC_ChannelCfg(1);
|
||||
|
||||
for(int i = 0; i < 20; i++) {
|
||||
adcBuff[i] = ADC_ExcutSingleConver() + RoughCalib_Value;
|
||||
ret += adcBuff[i];
|
||||
}
|
||||
for(int i = 0; i < 20; i++) {
|
||||
PRINT("%d \n", adcBuff[i]);
|
||||
}
|
||||
|
||||
return ret / 20;
|
||||
}
|
||||
|
||||
static int is_charging()
|
||||
{
|
||||
GPIOA_ModeCfg(CHARGE_STT_PIN, GPIO_ModeIN_PU);
|
||||
return GPIOA_ReadPortPin(CHARGE_STT_PIN) == 0;
|
||||
}
|
||||
|
||||
static void disp_bat_stt(int bat_percent, int col, int row)
|
||||
{
|
||||
if (bat_percent < 0) {
|
||||
@@ -373,30 +323,6 @@ static void disp_bat_stt(int bat_percent, int col, int row)
|
||||
}
|
||||
}
|
||||
|
||||
#define ZERO_PERCENT_THRES (3.3)
|
||||
#define _100_PERCENT_THRES (4.2)
|
||||
#define ADC_MAX_VAL (4096.0) // 12 bit
|
||||
#define ADC_MAX_VOLT (2.1) // Volt
|
||||
#define R1 (182.0) // kOhm
|
||||
#define R2 (100.0) // kOhm
|
||||
#define PERCENT_RANGE (_100_PERCENT_THRES - ZERO_PERCENT_THRES)
|
||||
#define VOLT_DIV(v) ((v) / (R1 + R2) * R2) // Voltage divider
|
||||
#define VOLT_DIV_INV(v) ((v) / R2 * (R1 + R2)) // .. Inverse
|
||||
#define ADC2VOLT(raw) ((raw) / ADC_MAX_VAL * ADC_MAX_VOLT)
|
||||
#define VOLT2ADC(volt) ((volt) / ADC_MAX_VOLT * ADC_MAX_VAL)
|
||||
|
||||
static int bat_raw2percent(int r)
|
||||
{
|
||||
float vadc = ADC2VOLT(r);
|
||||
float vbat = VOLT_DIV_INV(vadc);
|
||||
float strip = vbat - ZERO_PERCENT_THRES;
|
||||
if (strip < PERCENT_RANGE) {
|
||||
// Negative values meaning the battery is not connected or died
|
||||
return (int)(strip / PERCENT_RANGE * 100.0);
|
||||
}
|
||||
return 100;
|
||||
}
|
||||
|
||||
static void fb_putchar(char c, int col, int row)
|
||||
{
|
||||
for (int i=0; i < 6; i++) {
|
||||
@@ -419,9 +345,9 @@ static void disp_charging()
|
||||
{
|
||||
int blink = 0;
|
||||
while (mode == BOOT) {
|
||||
int percent = bat_raw2percent(read_batt_raw());
|
||||
int percent = batt_raw2percent(batt_raw());
|
||||
|
||||
if (is_charging()) {
|
||||
if (charging_status()) {
|
||||
disp_bat_stt(blink ? percent : 0, 2, 2);
|
||||
if (ani_xbm_next_frame(&fabm_xbm, fb, 16, 0) == 0) {
|
||||
fb_puts(VERSION_ABBR, sizeof(VERSION_ABBR), 16, 2);
|
||||
@@ -460,6 +386,7 @@ int main()
|
||||
btn_onOnePress(KEY2, bm_transition);
|
||||
btn_onLongPress(KEY1, change_brightness);
|
||||
|
||||
power_init();
|
||||
disp_charging();
|
||||
|
||||
play_splash(&splash, 0, 0);
|
||||
|
||||
78
src/power.c
Normal file
78
src/power.c
Normal file
@@ -0,0 +1,78 @@
|
||||
#include <CH58xBLE_LIB.h>
|
||||
|
||||
#include "power.h"
|
||||
#include "button.h"
|
||||
|
||||
void poweroff()
|
||||
{
|
||||
// Stop wasting energy
|
||||
GPIOA_ModeCfg(GPIO_Pin_All, GPIO_ModeIN_Floating);
|
||||
GPIOB_ModeCfg(GPIO_Pin_All, GPIO_ModeIN_Floating);
|
||||
|
||||
// Configure wake-up
|
||||
GPIOA_ModeCfg(KEY1_PIN, GPIO_ModeIN_PD);
|
||||
GPIOA_ITModeCfg(KEY1_PIN, GPIO_ITMode_RiseEdge);
|
||||
GPIOA_ModeCfg(CHARGE_STT_PIN, GPIO_ModeIN_PU);
|
||||
GPIOA_ITModeCfg(CHARGE_STT_PIN, GPIO_ITMode_FallEdge);
|
||||
PFIC_EnableIRQ(GPIO_A_IRQn);
|
||||
PWR_PeriphWakeUpCfg(ENABLE, RB_SLP_GPIO_WAKE, Long_Delay);
|
||||
|
||||
/* Good bye */
|
||||
LowPower_Shutdown(0);
|
||||
}
|
||||
|
||||
void power_init()
|
||||
{
|
||||
GPIOA_ModeCfg(GPIO_Pin_5, GPIO_ModeIN_Floating);
|
||||
ADC_ExtSingleChSampInit(SampleFreq_3_2, ADC_PGA_0);
|
||||
|
||||
int16_t adc_calib = ADC_DataCalib_Rough();
|
||||
PRINT("RoughCalib_Value = %d \n", adc_calib);
|
||||
|
||||
ADC_ChannelCfg(1);
|
||||
}
|
||||
|
||||
int batt_raw()
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
PRINT("ADC reading: \n");
|
||||
uint16_t buf[20];
|
||||
for(int i = 0; i < 20; i++) {
|
||||
uint16_t adc = ADC_ExcutSingleConver();
|
||||
ret += adc;
|
||||
PRINT("%d \n", adc);
|
||||
}
|
||||
|
||||
return ret / 20;
|
||||
}
|
||||
|
||||
int charging_status()
|
||||
{
|
||||
GPIOA_ModeCfg(CHARGE_STT_PIN, GPIO_ModeIN_PU);
|
||||
return GPIOA_ReadPortPin(CHARGE_STT_PIN) == 0;
|
||||
}
|
||||
|
||||
#define ZERO_PERCENT_THRES (3.3)
|
||||
#define _100_PERCENT_THRES (4.2)
|
||||
#define ADC_MAX_VAL (4096.0) // 12 bit
|
||||
#define ADC_MAX_VOLT (2.1) // Volt
|
||||
#define R1 (182.0) // kOhm
|
||||
#define R2 (100.0) // kOhm
|
||||
#define PERCENT_RANGE (_100_PERCENT_THRES - ZERO_PERCENT_THRES)
|
||||
#define VOLT_DIV(v) ((v) / (R1 + R2) * R2) // Voltage divider
|
||||
#define VOLT_DIV_INV(v) ((v) / R2 * (R1 + R2)) // .. Inverse
|
||||
#define ADC2VOLT(raw) ((raw) / ADC_MAX_VAL * ADC_MAX_VOLT)
|
||||
#define VOLT2ADC(volt) ((volt) / ADC_MAX_VOLT * ADC_MAX_VAL)
|
||||
|
||||
int batt_raw2percent(int r)
|
||||
{
|
||||
float vadc = ADC2VOLT(r);
|
||||
float vbat = VOLT_DIV_INV(vadc);
|
||||
float strip = vbat - ZERO_PERCENT_THRES;
|
||||
if (strip < PERCENT_RANGE) {
|
||||
// Negative values meaning the battery is not connected or died
|
||||
return (int)(strip / PERCENT_RANGE * 100.0);
|
||||
}
|
||||
return 100;
|
||||
}
|
||||
@@ -1,11 +1,17 @@
|
||||
#ifndef __RESET_H__
|
||||
#define __RESET_H__
|
||||
|
||||
#define CHARGE_STT_PIN GPIO_Pin_0 // PA0
|
||||
|
||||
static inline void reset_jump()
|
||||
{
|
||||
asm volatile("j 0x00");
|
||||
}
|
||||
|
||||
void power_init();
|
||||
void poweroff();
|
||||
int batt_raw();
|
||||
int charging_status();
|
||||
int batt_raw2percent(int r);
|
||||
|
||||
#endif /* __RESET_H__ */
|
||||
|
||||
Reference in New Issue
Block a user