Add next gen profile and configurations (#67)
* fix: crash in picture animation * ble: add next gen profile * force read header from flash anyway * fix: bmlist: mem leak * feat: add reset option after legacy transfers
This commit is contained in:
parent
512134607b
commit
4e556ab11f
@ -369,28 +369,3 @@ void mDelaymS(uint16_t t)
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
int _write(int fd, char *buf, int size)
|
||||
{
|
||||
int i;
|
||||
for(i = 0; i < size; i++)
|
||||
{
|
||||
#if DEBUG == Debug_UART0
|
||||
while(R8_UART0_TFC == UART_FIFO_SIZE); /* 等待数据发送 */
|
||||
R8_UART0_THR = *buf++; /* 发送数据 */
|
||||
#elif DEBUG == Debug_UART1
|
||||
while(R8_UART1_TFC == UART_FIFO_SIZE); /* 等待数据发送 */
|
||||
R8_UART1_THR = *buf++; /* 发送数据 */
|
||||
#elif DEBUG == Debug_UART2
|
||||
while(R8_UART2_TFC == UART_FIFO_SIZE); /* 等待数据发送 */
|
||||
R8_UART2_THR = *buf++; /* 发送数据 */
|
||||
#elif DEBUG == Debug_UART3
|
||||
while(R8_UART3_TFC == UART_FIFO_SIZE); /* 等待数据发送 */
|
||||
R8_UART3_THR = *buf++; /* 发送数据 */
|
||||
#endif
|
||||
}
|
||||
return size;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
@ -123,12 +123,6 @@ typedef volatile unsigned long long *PUINT64V;
|
||||
#define max(a,b) (((a) > (b)) ? (a) : (b))
|
||||
#endif
|
||||
|
||||
#ifdef DEBUG
|
||||
#define PRINT(X...) printf(X)
|
||||
#else
|
||||
#define PRINT(X...)
|
||||
#endif
|
||||
|
||||
/* Calculate the byte offset of a field in a structure of type */
|
||||
#define FIELD_OFFSET(Type, Field) ((UINT16)&(((Type *)0)->Field))
|
||||
|
||||
|
||||
@ -36,15 +36,6 @@
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#define Debug_UART0 0
|
||||
#define Debug_UART1 1
|
||||
#define Debug_UART2 2
|
||||
#define Debug_UART3 3
|
||||
|
||||
#ifdef DEBUG
|
||||
#include <stdio.h>
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief 系统主频时钟(Hz)
|
||||
*/
|
||||
|
||||
10
Makefile
10
Makefile
@ -47,25 +47,27 @@ CH5xx_ble_firmware_library/StdPeriphDriver/CH58x_clk.c \
|
||||
CH5xx_ble_firmware_library/StdPeriphDriver/CH58x_uart0.c \
|
||||
CH5xx_ble_firmware_library/StdPeriphDriver/CH58x_timer1.c \
|
||||
CH5xx_ble_firmware_library/StdPeriphDriver/CH58x_pwm.c \
|
||||
CH5xx_ble_firmware_library/StdPeriphDriver/CH58x_usbhostClass.c \
|
||||
CH5xx_ble_firmware_library/StdPeriphDriver/CH58x_adc.c \
|
||||
CH5xx_ble_firmware_library/StdPeriphDriver/CH58x_usbhostBase.c \
|
||||
CH5xx_ble_firmware_library/StdPeriphDriver/CH58x_timer3.c \
|
||||
CH5xx_ble_firmware_library/StdPeriphDriver/CH58x_timer0.c \
|
||||
CH5xx_ble_firmware_library/StdPeriphDriver/CH58x_usb2hostClass.c \
|
||||
CH5xx_ble_firmware_library/StdPeriphDriver/CH58x_flash.c \
|
||||
CH5xx_ble_firmware_library/StdPeriphDriver/CH58x_uart1.c \
|
||||
CH5xx_ble_firmware_library/StdPeriphDriver/CH58x_usb2dev.c \
|
||||
CH5xx_ble_firmware_library/StdPeriphDriver/CH58x_usb2hostBase.c \
|
||||
CH5xx_ble_firmware_library/StdPeriphDriver/CH58x_spi1.c \
|
||||
CH5xx_ble_firmware_library/RVMSIS/core_riscv.c \
|
||||
src/main.c \
|
||||
src/debug.c \
|
||||
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/profile/ng.c \
|
||||
src/config.c \
|
||||
src/legacyctrl.c \
|
||||
src/util/crc.c \
|
||||
src/ngctrl.c \
|
||||
src/ble/setup.c \
|
||||
src/ble/peripheral.c \
|
||||
src/data.c \
|
||||
|
||||
@ -3,6 +3,7 @@
|
||||
#include "xbm.h"
|
||||
#include "leddrv.h"
|
||||
#include "bmlist.h"
|
||||
#include "debug.h"
|
||||
|
||||
#define ANI_ANIMATION_STEPS (5) // steps
|
||||
#define ANI_FIXED_STEPS (LED_COLS) // steps
|
||||
@ -404,7 +405,7 @@ static void picture(bm_t *bm, uint16_t *fb, int step, int frame)
|
||||
int hc = LED_COLS / 2;
|
||||
int range = mod(step - 1, LED_COLS);
|
||||
|
||||
if (range > LED_COLS/2) {
|
||||
if (range > hc) {
|
||||
still(bm, fb, frame);
|
||||
return;
|
||||
}
|
||||
@ -418,15 +419,10 @@ static void picture(bm_t *bm, uint16_t *fb, int step, int frame)
|
||||
0 : bm->buf[hc - i + frame];
|
||||
}
|
||||
|
||||
if (i >= LED_COLS)
|
||||
if (i >= hc)
|
||||
return;
|
||||
fb[hc + i - 1] = -1;
|
||||
fb[hc - i] = -1;
|
||||
|
||||
for (i++; i< LED_COLS; i++) {
|
||||
fb[hc + i - 1] = 0;
|
||||
fb[hc - i] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static void picture_out(bm_t *bm, uint16_t *fb, int step)
|
||||
@ -442,7 +438,7 @@ static void picture_out(bm_t *bm, uint16_t *fb, int step)
|
||||
fb[hc + i - 1] = 0;
|
||||
fb[hc - i] = 0;
|
||||
}
|
||||
if (i >= LED_COLS)
|
||||
if (i >= hc)
|
||||
return;
|
||||
fb[hc + i - 1] = -1;
|
||||
fb[hc - i] = -1;
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
#include "CH58xBLE_LIB.h"
|
||||
#include "setup.h"
|
||||
#include "../config.h"
|
||||
|
||||
#define ADV_UUID (0xFEE0)
|
||||
|
||||
@ -24,29 +25,6 @@ typedef struct
|
||||
|
||||
#define CONN_TIMEOUT 100 // Supervision timeout (units of 10ms)
|
||||
|
||||
// GAP - SCAN RSP data (max size = 31 bytes)
|
||||
static uint8 scanRspData[] = {
|
||||
// complete name
|
||||
16, // length of this section
|
||||
GAP_ADTYPE_LOCAL_NAME_COMPLETE,
|
||||
'L', 'E','D', ' ',
|
||||
'B', 'a','d', 'g', 'e', ' ',
|
||||
'M', 'a','g', 'i', 'c',
|
||||
|
||||
// connection interval range
|
||||
0x05, // length of this section
|
||||
GAP_ADTYPE_SLAVE_CONN_INTERVAL_RANGE,
|
||||
LO_UINT16(MIN_CONN_INTERVAL),
|
||||
HI_UINT16(MIN_CONN_INTERVAL),
|
||||
LO_UINT16(MAX_CONN_INTERVAL),
|
||||
HI_UINT16(MAX_CONN_INTERVAL),
|
||||
|
||||
// Tx power level
|
||||
0x02, // length of this data
|
||||
GAP_ADTYPE_POWER_LEVEL,
|
||||
9 // 9dBm
|
||||
};
|
||||
|
||||
// GAP - Advertisement data (max size = 31 bytes)
|
||||
// keep short, save energy, save the planet
|
||||
static uint8 advertData[] = {
|
||||
@ -61,9 +39,6 @@ static uint8 advertData[] = {
|
||||
HI_UINT16(ADV_UUID)
|
||||
};
|
||||
|
||||
// GAP GATT Attributes
|
||||
static uint8 devName[GAP_DEVICE_NAME_LEN] = "LED Badge Magic";
|
||||
|
||||
// Connection item list
|
||||
static peripheralConnItem_t conn_list;
|
||||
|
||||
@ -210,21 +185,58 @@ void ble_disable_advertise()
|
||||
GAPRole_SetParameter(GAPROLE_ADVERT_ENABLED, sizeof(uint8), &e);
|
||||
}
|
||||
|
||||
// len should not exceed 20 chars excluding null-terminate char. Otherwise it
|
||||
// will be trimmed off and return -1
|
||||
static int setup_scan_rsp(char *name, uint8_t len)
|
||||
{
|
||||
int ret = 0;
|
||||
// GAP - SCAN RSP data (max size = 31 bytes)
|
||||
uint8_t scanRspData[31] = {
|
||||
// connection interval range
|
||||
0x05, // length of this section
|
||||
GAP_ADTYPE_SLAVE_CONN_INTERVAL_RANGE,
|
||||
LO_UINT16(MIN_CONN_INTERVAL),
|
||||
HI_UINT16(MIN_CONN_INTERVAL),
|
||||
LO_UINT16(MAX_CONN_INTERVAL),
|
||||
HI_UINT16(MAX_CONN_INTERVAL),
|
||||
|
||||
// Tx power level
|
||||
0x02, // length of this data
|
||||
GAP_ADTYPE_POWER_LEVEL,
|
||||
9, // 9dBm
|
||||
|
||||
len + 1,
|
||||
GAP_ADTYPE_LOCAL_NAME_COMPLETE,
|
||||
};
|
||||
|
||||
if (len < (31 - 11)) {
|
||||
tmos_memcpy(&scanRspData[11], name, len);
|
||||
ret = -1;
|
||||
} else {
|
||||
tmos_memcpy(&scanRspData[11], name, 20);
|
||||
}
|
||||
int total_len = 11 + len;
|
||||
tmos_memset(&scanRspData[total_len], 0, 31 - total_len);
|
||||
GAPRole_SetParameter(GAPROLE_SCAN_RSP_DATA, total_len, scanRspData);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void gap_init()
|
||||
{
|
||||
GAPRole_PeripheralInit();
|
||||
|
||||
static uint16 desired_min_interval = 6;
|
||||
static uint16 desired_max_interval = 500;
|
||||
uint16_t min_interval = 6;
|
||||
uint16_t max_interval = 500;
|
||||
|
||||
// Set the GAP Role Parameters
|
||||
GAPRole_SetParameter(GAPROLE_SCAN_RSP_DATA, sizeof(scanRspData), scanRspData);
|
||||
setup_scan_rsp(badge_cfg.ble_devname, 20);
|
||||
GAPRole_SetParameter(GAPROLE_ADVERT_DATA, sizeof(advertData), advertData);
|
||||
GAPRole_SetParameter(GAPROLE_MIN_CONN_INTERVAL, sizeof(uint16), &desired_min_interval);
|
||||
GAPRole_SetParameter(GAPROLE_MAX_CONN_INTERVAL, sizeof(uint16), &desired_max_interval);
|
||||
GAPRole_SetParameter(GAPROLE_MIN_CONN_INTERVAL, sizeof(uint16), &min_interval);
|
||||
GAPRole_SetParameter(GAPROLE_MAX_CONN_INTERVAL, sizeof(uint16), &max_interval);
|
||||
|
||||
// Set the GAP Characteristics
|
||||
GGS_SetParameter(GGS_DEVICE_NAME_ATT, GAP_DEVICE_NAME_LEN, devName);
|
||||
GGS_SetParameter(GGS_DEVICE_NAME_ATT, 20,
|
||||
badge_cfg.ble_devname);
|
||||
GAP_SetParamValue(TGAP_DISC_ADV_INT_MIN, MIN_ADV_INTERVAL);
|
||||
GAP_SetParamValue(TGAP_DISC_ADV_INT_MAX, MAX_ADV_INTERVAL);
|
||||
|
||||
|
||||
@ -4,5 +4,8 @@
|
||||
int legacy_registerService();
|
||||
int devInfo_registerService();
|
||||
int batt_registerService();
|
||||
int ng_registerService();
|
||||
|
||||
bStatus_t ng_notify(uint8_t *pValue, uint8_t len);
|
||||
|
||||
#endif /* __BLE_UART_SERVICE_H__ */
|
||||
|
||||
@ -1,8 +1,6 @@
|
||||
#include "utils.h"
|
||||
|
||||
#include "../../data.h"
|
||||
#include "../../power.h"
|
||||
#include "../../leddrv.h"
|
||||
#include "../../legacyctrl.h"
|
||||
|
||||
static const uint16_t ServiceUUID = 0xFEE0;
|
||||
static const gattAttrType_t service = {2, (uint8_t *)&ServiceUUID};
|
||||
@ -18,39 +16,6 @@ static gattAttribute_t attr_table[] = {
|
||||
CHAR_VAL_DECLAR(&RxCharUUID, 2, GATT_PERMIT_WRITE, RxCharVal),
|
||||
};
|
||||
|
||||
static bStatus_t receive(uint8_t *val, uint16_t len)
|
||||
{
|
||||
static uint16_t c, data_len, n;
|
||||
static uint8_t *data;
|
||||
if (len != LEGACY_TRANSFER_WIDTH) {
|
||||
return ATT_ERR_INVALID_VALUE_SIZE;
|
||||
}
|
||||
if (c == 0) {
|
||||
if (memcmp(val, "wang\0\0", 6)) {
|
||||
return ATT_ERR_INVALID_VALUE;
|
||||
} else {
|
||||
data = malloc(sizeof(data_legacy_t));
|
||||
}
|
||||
}
|
||||
|
||||
memcpy(data + c * len, val, len);
|
||||
|
||||
if (c == 1) {
|
||||
data_legacy_t *d = (data_legacy_t *)data;
|
||||
n = bigendian16_sum(d->sizes, 8);
|
||||
data_len = LEGACY_HEADER_SIZE + LED_ROWS * n;
|
||||
data = realloc(data, data_len);
|
||||
}
|
||||
|
||||
if (c > 2 && ((c+1) * LEGACY_TRANSFER_WIDTH) >= data_len) {
|
||||
data_flatSave(data, data_len);
|
||||
reset_jump();
|
||||
}
|
||||
|
||||
c++;
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
static bStatus_t write_handler(uint16 connHandle, gattAttribute_t *pAttr,
|
||||
uint8 *pValue, uint16 len, uint16 offset, uint8 method)
|
||||
{
|
||||
@ -60,7 +25,10 @@ static bStatus_t write_handler(uint16 connHandle, gattAttribute_t *pAttr,
|
||||
|
||||
uint16_t uuid = BUILD_UINT16(pAttr->type.uuid[0], pAttr->type.uuid[1]);
|
||||
if(uuid == RxCharUUID) {
|
||||
return receive(pValue, len);
|
||||
if (legacy_ble_rx(pValue, len)) {
|
||||
return ATT_ERR_UNLIKELY;
|
||||
}
|
||||
return SUCCESS;
|
||||
}
|
||||
return ATT_ERR_ATTR_NOT_FOUND;
|
||||
}
|
||||
|
||||
160
src/ble/profile/ng.c
Normal file
160
src/ble/profile/ng.c
Normal file
@ -0,0 +1,160 @@
|
||||
#include "utils.h"
|
||||
|
||||
#include "CH583SFR.h"
|
||||
|
||||
#include "../../power.h"
|
||||
#include "../../ngctrl.h"
|
||||
#include "../../debug.h"
|
||||
|
||||
static const uint16_t ServiceUUID = 0xF055;
|
||||
static const gattAttrType_t service = {2, (uint8_t *)&ServiceUUID};
|
||||
|
||||
static const uint16_t TxCharUUID = 0xF056;
|
||||
static uint8_t TxCharProps = GATT_PROP_READ | GATT_PROP_NOTIFY;
|
||||
static uint8_t TxCharVal[256];
|
||||
static uint16_t TxLen;
|
||||
|
||||
static const uint16_t RxCharUUID = 0xF057;
|
||||
static uint8_t RxCharProps = GATT_PROP_WRITE;
|
||||
#define RxCharVal TxCharVal
|
||||
static gattCharCfg_t TxCCCD[1];
|
||||
|
||||
static gattAttribute_t attr_table[] = {
|
||||
ATTR_DECLAR(primaryServiceUUID, 2, GATT_PERMIT_READ, &service),
|
||||
|
||||
CHAR_DECLAR(&RxCharProps),
|
||||
CHAR_VAL_DECLAR(&RxCharUUID, 2, GATT_PERMIT_WRITE, RxCharVal),
|
||||
|
||||
CHAR_DECLAR(&TxCharProps),
|
||||
CHAR_VAL_DECLAR(&TxCharUUID, 2, GATT_PERMIT_READ, TxCharVal),
|
||||
ATTR_DECLAR(clientCharCfgUUID, 2, GATT_PERMIT_READ | GATT_PERMIT_WRITE, TxCCCD),
|
||||
};
|
||||
|
||||
#define notiAttr attr_table[4]
|
||||
|
||||
|
||||
static bStatus_t write_handler(uint16 connHandle, gattAttribute_t *pAttr,
|
||||
uint8 *pValue, uint16 len, uint16 offset, uint8 method)
|
||||
{
|
||||
PRINT("ble: write_handler(): connHandle: %04X\n", connHandle);
|
||||
|
||||
if (!gattPermitWrite(pAttr->permissions)) {
|
||||
return ATT_ERR_WRITE_NOT_PERMITTED;
|
||||
}
|
||||
|
||||
uint16_t uuid = BUILD_UINT16(pAttr->type.uuid[0], pAttr->type.uuid[1]);
|
||||
if(uuid == GATT_CLIENT_CHAR_CFG_UUID) {
|
||||
bStatus_t ret = GATTServApp_ProcessCCCWriteReq(connHandle, pAttr, pValue, len,
|
||||
offset, GATT_CLIENT_CFG_NOTIFY);
|
||||
PRINT("ble: CCCD changed: %02X\n", TxCCCD->value);
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (uuid == RxCharUUID) {
|
||||
return ng_parse(pValue, len);
|
||||
}
|
||||
|
||||
return ATT_ERR_ATTR_NOT_FOUND;
|
||||
}
|
||||
|
||||
static bStatus_t read_handler(uint16_t connHandle, gattAttribute_t *pAttr,
|
||||
uint8_t *pValue, uint16_t *pLen, uint16_t offset,
|
||||
uint16_t maxLen, uint8_t method)
|
||||
{
|
||||
if (!gattPermitRead(pAttr->permissions)) {
|
||||
return ATT_ERR_READ_NOT_PERMITTED;
|
||||
}
|
||||
|
||||
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, *pLen);
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
if (uuid == TxCharUUID) {
|
||||
*pLen = MIN(TxLen-offset, maxLen);
|
||||
tmos_memcpy(pValue, &pAttr->pValue[offset], *pLen);
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
return ATT_ERR_ATTR_NOT_FOUND;
|
||||
}
|
||||
|
||||
static gattServiceCBs_t service_handlers = {
|
||||
read_handler,
|
||||
write_handler,
|
||||
NULL
|
||||
};
|
||||
|
||||
static void connStatus_handler(uint16 connHandle, uint8 changeType)
|
||||
{
|
||||
if(connHandle == LOOPBACK_CONNHANDLE)
|
||||
return;
|
||||
|
||||
// Reset ClientCharConfig if connection has dropped
|
||||
if((changeType == LINKDB_STATUS_UPDATE_REMOVED)
|
||||
|| ((changeType == LINKDB_STATUS_UPDATE_STATEFLAGS)
|
||||
&& (!linkDB_Up(connHandle)))) {
|
||||
GATTServApp_InitCharCfg(connHandle, TxCCCD);
|
||||
}
|
||||
}
|
||||
|
||||
int ng_registerService()
|
||||
{
|
||||
uint8 status = SUCCESS;
|
||||
GATTServApp_InitCharCfg(INVALID_CONNHANDLE, TxCCCD);
|
||||
linkDB_Register(connStatus_handler);
|
||||
|
||||
status = GATTServApp_RegisterService(attr_table,
|
||||
GATT_NUM_ATTRS(attr_table),
|
||||
GATT_MAX_ENCRYPT_KEY_SIZE,
|
||||
&service_handlers);
|
||||
return (status);
|
||||
}
|
||||
|
||||
static uint8 isNotifyEnabled(uint16 connHandle)
|
||||
{
|
||||
uint16_t val = GATTServApp_ReadCharCfg(connHandle, TxCCCD);
|
||||
return val & GATT_CLIENT_CFG_NOTIFY;
|
||||
}
|
||||
/**
|
||||
* @brief Send notify to client. Currently support one client connection
|
||||
* only.
|
||||
*
|
||||
* @param val Value to be sent
|
||||
* @param len length of val. This should not be larger than MTU.
|
||||
* @return bStatus_t
|
||||
*/
|
||||
bStatus_t ng_notify(uint8_t *val, uint8_t len)
|
||||
{
|
||||
if(!isNotifyEnabled(TxCCCD->connHandle)) {
|
||||
PRINT("ble: ng_notify() notify is not enabled\n");
|
||||
return bleIncorrectMode;
|
||||
}
|
||||
if(len > ATT_GetMTU(TxCCCD->connHandle)) {
|
||||
return bleInvalidRange;
|
||||
}
|
||||
|
||||
attHandleValueNoti_t noti = {
|
||||
.handle = notiAttr.handle,
|
||||
.len = len
|
||||
};
|
||||
noti.pValue = GATT_bm_alloc(TxCCCD->connHandle, ATT_HANDLE_VALUE_NOTI,
|
||||
len, NULL, 0);
|
||||
if (noti.pValue == NULL) {
|
||||
return bleMemAllocError;
|
||||
}
|
||||
|
||||
tmos_memcpy(noti.pValue, val, len);
|
||||
|
||||
bStatus_t ret = GATT_Notification(TxCCCD->connHandle, ¬i, FALSE);
|
||||
GATT_bm_free((gattMsg_t *)¬i, ATT_HANDLE_VALUE_NOTI);
|
||||
if (ret != SUCCESS) {
|
||||
PRINT("ble: noti sending failed\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
PRINT("ble: noti sent\n");
|
||||
return SUCCESS;
|
||||
}
|
||||
@ -6,28 +6,39 @@
|
||||
#include "CH58x_common.h"
|
||||
|
||||
#ifndef BLE_BUFF_LEN
|
||||
#define BLE_BUFF_LEN 27
|
||||
#endif
|
||||
#ifndef BLE_BUFF_NUM
|
||||
#define BLE_BUFF_NUM 5
|
||||
// MTU = 64 but clients should request new MTU, otherwise default will be 23
|
||||
#define BLE_BUFF_LEN (64 + 4)
|
||||
#endif
|
||||
|
||||
#ifndef BLE_TX_NUM_EVENT
|
||||
#define BLE_TX_NUM_EVENT 1
|
||||
#endif
|
||||
|
||||
#ifndef BLE_TX_POWER
|
||||
#define BLE_TX_POWER LL_TX_POWEER_6_DBM
|
||||
// #define BLE_TX_POWER LL_TX_POWEER_MINUS_16_DBM
|
||||
#endif
|
||||
|
||||
#ifndef BLE_MEMHEAP_SIZE
|
||||
#define BLE_MEMHEAP_SIZE (1024*6)
|
||||
#define BLE_MEMHEAP_SIZE (1024 * 6)
|
||||
#endif
|
||||
|
||||
#ifndef CENTRAL_MAX_CONNECTION
|
||||
#define CENTRAL_MAX_CONNECTION 3
|
||||
#define CENTRAL_MAX_CONNECTION 1
|
||||
#endif
|
||||
|
||||
#ifndef BLE_BUFF_NUM
|
||||
// The BLE lib automatically stack up Write Long messages in Write handler.
|
||||
// A connection will be disconnected if this number is some how not enough.
|
||||
#define BLE_BUFF_NUM (512 / 23)
|
||||
#endif
|
||||
|
||||
#ifndef PERIPHERAL_MAX_CONNECTION
|
||||
#define PERIPHERAL_MAX_CONNECTION 1
|
||||
#endif
|
||||
|
||||
static __attribute__((aligned(4))) uint32_t MEM_BUF[BLE_MEMHEAP_SIZE / 4];
|
||||
static __attribute__((aligned(4), section(".noinit")))
|
||||
uint32_t MEM_BUF[BLE_MEMHEAP_SIZE / 4];
|
||||
|
||||
static void lsi_calib(void)
|
||||
{
|
||||
|
||||
@ -68,6 +68,7 @@ bm_t *bmlist_drop(bm_t *bm)
|
||||
head = bm->next;
|
||||
if (bm == tail)
|
||||
tail = bm->prev;
|
||||
free(bm);
|
||||
return bm->next;
|
||||
}
|
||||
|
||||
|
||||
87
src/config.c
Normal file
87
src/config.c
Normal file
@ -0,0 +1,87 @@
|
||||
/**
|
||||
* TODO: needs constraints checking as some of the config fields may have
|
||||
* invalid values which will make the badge broke.
|
||||
*/
|
||||
#include "config.h"
|
||||
#include "resource.h"
|
||||
#include "res/foss-asia-2.xbm"
|
||||
#include "debug.h"
|
||||
#include "util/crc.h"
|
||||
|
||||
#include "ISP583.h"
|
||||
#include <stdlib.h>
|
||||
|
||||
#define CFG_SIZE sizeof(badge_cfg_t)
|
||||
#define CFG_DEF_FLASH_OFFS (EEPROM_MAX_SIZE - CFG_SIZE - 1) // Default offset
|
||||
|
||||
badge_cfg_t badge_cfg;
|
||||
|
||||
/* In case of first time firmware upgrading */
|
||||
void cfg_fallback()
|
||||
{
|
||||
badge_cfg.ble_always_on = 1;
|
||||
memcpy(badge_cfg.ble_devname, "LED Badge Magic\0\0\0\0", 20);
|
||||
/* OEM app testing: */
|
||||
// memcpy(badge_cfg.ble_devname, "LSLED\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 20);
|
||||
|
||||
badge_cfg.led_brightness = 0;
|
||||
badge_cfg.led_scan_freq = 2000;
|
||||
|
||||
badge_cfg.splash_speedT = 30; // ms
|
||||
|
||||
int splash_size = ALIGN_1BYTE(splash.w) * splash.h;
|
||||
memcpy(badge_cfg.splash_bm_bits, splash.bits, splash_size);
|
||||
badge_cfg.splash_bm_w = splash.w;
|
||||
badge_cfg.splash_bm_h = splash.h;
|
||||
badge_cfg.splash_bm_fh = splash.fh;
|
||||
|
||||
badge_cfg.reset_rx = FALSE;
|
||||
}
|
||||
|
||||
void cfg_update_crc(badge_cfg_t *cfg)
|
||||
{
|
||||
cfg->crc = crc_cal((uint8_t *)cfg, CFG_SIZE - 1);
|
||||
PRINT(__func__);
|
||||
PRINT(": crc: %02X\n", cfg->crc);
|
||||
}
|
||||
|
||||
int cfg_writeflash(uint16_t flash_offs, badge_cfg_t *cfg)
|
||||
{
|
||||
if (flash_offs + CFG_SIZE > EEPROM_MAX_SIZE) {
|
||||
return -1;
|
||||
}
|
||||
cfg_update_crc(&badge_cfg);
|
||||
return EEPROM_WRITE(flash_offs, cfg, CFG_SIZE);
|
||||
}
|
||||
|
||||
int cfg_readflash(uint16_t flash_offs, badge_cfg_t *cfg)
|
||||
{
|
||||
int ret = EEPROM_READ(flash_offs, cfg, CFG_SIZE);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return crc_cal((uint8_t *)cfg, CFG_SIZE);
|
||||
}
|
||||
|
||||
int cfg_readflash_def(badge_cfg_t *cfg)
|
||||
{
|
||||
return cfg_readflash(CFG_DEF_FLASH_OFFS, cfg);
|
||||
}
|
||||
|
||||
int cfg_writeflash_def(badge_cfg_t *cfg)
|
||||
{
|
||||
return cfg_writeflash(CFG_DEF_FLASH_OFFS, cfg);
|
||||
}
|
||||
|
||||
void cfg_init()
|
||||
{
|
||||
badge_cfg_t cfg;
|
||||
int r = cfg_readflash_def(&cfg);
|
||||
if (r) {
|
||||
cfg_fallback();
|
||||
PRINT("configuration falling back: %02x\n", r);
|
||||
} else {
|
||||
memcpy(&badge_cfg, &cfg, CFG_SIZE);
|
||||
PRINT("configuration read from flash successfully\n");
|
||||
}
|
||||
}
|
||||
42
src/config.h
Normal file
42
src/config.h
Normal file
@ -0,0 +1,42 @@
|
||||
#ifndef __CONFIG_H__
|
||||
#define __CONFIG_H__
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include "xbm.h"
|
||||
#include "leddrv.h"
|
||||
|
||||
#define SPLASH_MAX_WIDTH (48) // pixels
|
||||
#define SPLASH_MAX_HEIGHT (44) // pixels
|
||||
#define SPLASH_MAX_SIZE (ALIGN_1BYTE(SPLASH_MAX_WIDTH) * SPLASH_MAX_HEIGHT)
|
||||
|
||||
typedef struct {
|
||||
// Turn on Bluetooth while in Normal mode and disable Downloads mode
|
||||
uint8_t ble_always_on;
|
||||
char ble_devname[20];
|
||||
|
||||
uint8_t led_brightness;
|
||||
uint16_t led_scan_freq; // Scan frequency
|
||||
|
||||
uint8_t splash_bm_bits[SPLASH_MAX_SIZE]; // Up to 48x44 (Width x Height)
|
||||
uint8_t splash_bm_w;
|
||||
uint8_t splash_bm_h;
|
||||
uint8_t splash_bm_fh;
|
||||
|
||||
// Speed in period of micro second. The lower value, the higher speed
|
||||
uint16_t splash_speedT;
|
||||
uint8_t reset_rx; // Reset after bitmap received
|
||||
|
||||
uint8_t crc;
|
||||
} __attribute__((packed)) badge_cfg_t;
|
||||
|
||||
extern badge_cfg_t badge_cfg;
|
||||
|
||||
void cfg_init();
|
||||
int cfg_writeflash(uint16_t flash_offs, badge_cfg_t *cfg);
|
||||
int cfg_readflash(uint16_t flash_offs, badge_cfg_t *cfg);
|
||||
int cfg_writeflash_def(badge_cfg_t *cfg);
|
||||
int cfg_readflash_def(badge_cfg_t *cfg);
|
||||
void cfg_fallback();
|
||||
|
||||
#endif /* __CONFIG_H__ */
|
||||
32
src/data.c
32
src/data.c
@ -24,34 +24,25 @@ uint32_t data_flatSave(uint8_t *data, uint32_t len)
|
||||
return EEPROM_WRITE(0, data, len);
|
||||
}
|
||||
|
||||
data_legacy_t *data_get_header(int read_anyway)
|
||||
void data_get_header(data_legacy_t *buf)
|
||||
{
|
||||
static data_legacy_t *cache;
|
||||
|
||||
if (cache == NULL) {
|
||||
cache = malloc(sizeof(data_legacy_t));
|
||||
read_anyway = 1;
|
||||
}
|
||||
|
||||
if (read_anyway) {
|
||||
EEPROM_READ(0, cache, LEGACY_HEADER_SIZE);
|
||||
}
|
||||
return cache;
|
||||
EEPROM_READ(0, buf, LEGACY_HEADER_SIZE);
|
||||
}
|
||||
|
||||
uint16_t data_flash2newmem(uint8_t **chunk, uint32_t n)
|
||||
{
|
||||
data_legacy_t *header = data_get_header(0);
|
||||
data_legacy_t header;
|
||||
data_get_header(&header);
|
||||
|
||||
if (memcmp(header->header, "wang", 5))
|
||||
if (memcmp(header.header, "wang", 5))
|
||||
return 0;
|
||||
|
||||
uint16_t size = bswap16(header->sizes[n]) * LED_ROWS;
|
||||
uint16_t size = bswap16(header.sizes[n]) * LED_ROWS;
|
||||
if (size == 0)
|
||||
return 0;
|
||||
|
||||
uint16_t offs = LEGACY_HEADER_SIZE
|
||||
+ bigendian16_sum(header->sizes, n) * LED_ROWS;
|
||||
+ bigendian16_sum(header.sizes, n) * LED_ROWS;
|
||||
|
||||
*chunk = malloc(size);
|
||||
EEPROM_READ(offs, *chunk, size);
|
||||
@ -98,11 +89,12 @@ bm_t *flash2newbm(uint32_t n)
|
||||
return NULL;
|
||||
|
||||
bm_t *bm = chunk2newbm(buf, size);
|
||||
data_legacy_t *header = data_get_header(0);
|
||||
data_legacy_t header;
|
||||
data_get_header(&header);
|
||||
|
||||
bm->is_flash = (header->flash & (1 << n)) != 0;
|
||||
bm->is_marquee = (header->marquee & (1 << n)) != 0;
|
||||
bm->modes = header->modes[n];
|
||||
bm->is_flash = (header.flash & (1 << n)) != 0;
|
||||
bm->is_marquee = (header.marquee & (1 << n)) != 0;
|
||||
bm->modes = header.modes[n];
|
||||
|
||||
free(buf);
|
||||
return bm;
|
||||
|
||||
@ -20,7 +20,7 @@ typedef struct {
|
||||
uint8_t separator[16];
|
||||
|
||||
uint8_t *bitmapdata;
|
||||
} data_legacy_t;
|
||||
} __attribute__((packed)) data_legacy_t;
|
||||
|
||||
#define LEGACY_TRANSFER_WIDTH (16)
|
||||
#define LEGACY_HEADER_SIZE (sizeof(data_legacy_t) - sizeof(uint8_t *))
|
||||
@ -47,7 +47,7 @@ uint32_t bigendian16_sum(uint16_t *s, int len);
|
||||
uint32_t data_flatSave(uint8_t *data, uint32_t len);
|
||||
uint16_t data_flash2newmem(uint8_t **chunk, uint32_t n);
|
||||
|
||||
data_legacy_t *data_get_header(int read_anyway);
|
||||
void data_get_header(data_legacy_t *buf);
|
||||
|
||||
void chunk2buffer(uint8_t *chunk, uint16_t size, uint16_t *buf);
|
||||
void chunk2bm(uint8_t *chunk, uint16_t size, bm_t *bm);
|
||||
|
||||
35
src/debug.c
Normal file
35
src/debug.c
Normal file
@ -0,0 +1,35 @@
|
||||
#include "debug.h"
|
||||
#include "CH583SFR.h"
|
||||
|
||||
#ifdef DEBUG
|
||||
|
||||
#define Debug_UART0 0
|
||||
#define Debug_UART1 1
|
||||
#define Debug_UART2 2
|
||||
#define Debug_UART3 3
|
||||
|
||||
int _write(int fd, char *buf, int size)
|
||||
{
|
||||
int i;
|
||||
for(i = 0; i < size; i++)
|
||||
{
|
||||
#if DEBUG == Debug_UART0
|
||||
while(R8_UART0_TFC == UART_FIFO_SIZE);
|
||||
R8_UART0_THR = *buf++;
|
||||
#elif DEBUG == Debug_UART1
|
||||
while(R8_UART1_TFC == UART_FIFO_SIZE);
|
||||
R8_UART1_THR = *buf++;
|
||||
#elif DEBUG == Debug_UART2
|
||||
while(R8_UART2_TFC == UART_FIFO_SIZE);
|
||||
R8_UART2_THR = *buf++;
|
||||
#elif DEBUG == Debug_UART3
|
||||
while(R8_UART3_TFC == UART_FIFO_SIZE);
|
||||
R8_UART3_THR = *buf++;
|
||||
#else
|
||||
#error "Please specify a debug port for uart"
|
||||
#endif
|
||||
}
|
||||
return size;
|
||||
}
|
||||
|
||||
#endif
|
||||
15
src/debug.h
Normal file
15
src/debug.h
Normal file
@ -0,0 +1,15 @@
|
||||
#ifndef __DEBUG_H__
|
||||
#define __DEBUG_H__
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#ifdef DEBUG
|
||||
#define PRINT(X...) printf(X)
|
||||
#else
|
||||
#define PRINT(X...)
|
||||
#endif
|
||||
|
||||
#define _TRACE() PRINT("> "); PRINT(__FILE__); PRINT(": "); PRINT(__func__); \
|
||||
PRINT("()\n")
|
||||
|
||||
#endif /* __DEBUG_H__ */
|
||||
110
src/legacyctrl.c
Normal file
110
src/legacyctrl.c
Normal file
@ -0,0 +1,110 @@
|
||||
#include "data.h"
|
||||
#include "power.h"
|
||||
#include "leddrv.h"
|
||||
#include "debug.h"
|
||||
#include "legacyctrl.h"
|
||||
|
||||
int legacy_ble_rx(uint8_t *val, uint16_t len)
|
||||
{
|
||||
_TRACE();
|
||||
static uint16_t c, data_len, n;
|
||||
static uint8_t *data;
|
||||
|
||||
if (len != LEGACY_TRANSFER_WIDTH) {
|
||||
PRINT("Transfer width is not matched\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
PRINT("val[%d]: ", len);
|
||||
for (int i=0; i<len; i++) {
|
||||
PRINT("%02X ", val[i]);
|
||||
}
|
||||
PRINT("\n");
|
||||
|
||||
if (c == 0) {
|
||||
if (memcmp(val, "wang", 5)) {
|
||||
PRINT("Not a header\n");
|
||||
return -2;
|
||||
} else {
|
||||
free(data);
|
||||
data = malloc(sizeof(data_legacy_t));
|
||||
if (!data) {
|
||||
PRINT("insufficient memory\n");
|
||||
return -3;
|
||||
}
|
||||
}
|
||||
} else { // Re attempt after a failed transfer
|
||||
if (!memcmp(val, "wang", 5)) {
|
||||
free(data);
|
||||
c = 0;
|
||||
data = malloc(sizeof(data_legacy_t));
|
||||
if (!data) {
|
||||
PRINT("insufficient memory\n");
|
||||
return -3;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
PRINT("Copying BLE value\n");
|
||||
memcpy(data + c * len, val, len);
|
||||
|
||||
if (c == 1) {
|
||||
data_legacy_t *d = (data_legacy_t *)data;
|
||||
n = bigendian16_sum(d->sizes, 8);
|
||||
data_len = LEGACY_HEADER_SIZE + LED_ROWS * n;
|
||||
PRINT("Data len: %d\n", data_len);
|
||||
data = realloc(data, data_len);
|
||||
if (!data) {
|
||||
PRINT("insufficient memory\n");
|
||||
return -3;
|
||||
}
|
||||
}
|
||||
|
||||
if (c > 2 && ((c+1) * LEGACY_TRANSFER_WIDTH) >= data_len) {
|
||||
PRINT("All bitmaps data received successfully\nWriting to flash.. ");
|
||||
data_flatSave(data, data_len);
|
||||
free(data);
|
||||
data = NULL;
|
||||
handle_after_rx();
|
||||
PRINT("Done\n");
|
||||
}
|
||||
|
||||
c++;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int legacy_usb_rx(uint8_t *buf, uint16_t len)
|
||||
{
|
||||
static uint16_t rx_len, data_len;
|
||||
static uint8_t *data;
|
||||
|
||||
PRINT("dump first 8 bytes: %02x %02x %02x %02x %02x %02x %02x %02x\n",
|
||||
buf[0], buf[1], buf[2], buf[3],
|
||||
buf[4], buf[5], buf[6], buf[7]);
|
||||
|
||||
if (rx_len == 0) {
|
||||
if (memcmp(buf, "wang", 5))
|
||||
return -1;
|
||||
|
||||
int init_len = len > LEGACY_HEADER_SIZE ? len : sizeof(data_legacy_t);
|
||||
init_len += MAX_PACKET_SIZE;
|
||||
data = malloc(init_len);
|
||||
}
|
||||
|
||||
memcpy(data + rx_len, buf, len);
|
||||
rx_len += len;
|
||||
|
||||
if (!data_len) {
|
||||
data_legacy_t *d = (data_legacy_t *)data;
|
||||
uint16_t n = bigendian16_sum(d->sizes, 8);
|
||||
data_len = LEGACY_HEADER_SIZE + LED_ROWS * n;
|
||||
data = realloc(data, data_len);
|
||||
}
|
||||
|
||||
if ((rx_len > LEGACY_HEADER_SIZE) && rx_len >= data_len) {
|
||||
data_flatSave(data, data_len);
|
||||
free(data);
|
||||
handle_after_rx();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
10
src/legacyctrl.h
Normal file
10
src/legacyctrl.h
Normal file
@ -0,0 +1,10 @@
|
||||
#ifndef __LEGACYCTRL_H__
|
||||
#define __LEGACYCTRL_H__
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
void handle_after_rx();
|
||||
int legacy_ble_rx(uint8_t *val, uint16_t len);
|
||||
int legacy_usb_rx(uint8_t *buf, uint16_t len);
|
||||
|
||||
#endif /* __LEGACYCTRL_H__ */
|
||||
207
src/main.c
207
src/main.c
@ -11,14 +11,14 @@
|
||||
|
||||
#include "power.h"
|
||||
#include "data.h"
|
||||
#include "config.h"
|
||||
#include "debug.h"
|
||||
|
||||
#include "ble/setup.h"
|
||||
#include "ble/profile.h"
|
||||
|
||||
#include "usb/usb.h"
|
||||
|
||||
#define SCAN_F (2000)
|
||||
#define SCAN_T (FREQ_SYS / SCAN_F)
|
||||
#include "legacyctrl.h"
|
||||
|
||||
#define NEXT_STATE(v, min, max) \
|
||||
(v)++; \
|
||||
@ -60,10 +60,22 @@ static void change_brightness()
|
||||
NEXT_STATE(brightness, 0, BRIGHTNESS_LEVELS);
|
||||
}
|
||||
|
||||
static void mode_setup_download();
|
||||
static void mode_setup_normal();
|
||||
|
||||
__HIGH_CODE
|
||||
static void change_mode()
|
||||
{
|
||||
NEXT_STATE(mode, 0, MODES_COUNT);
|
||||
const static void (*modes[])(void) = {
|
||||
NULL,
|
||||
mode_setup_normal,
|
||||
mode_setup_download,
|
||||
poweroff
|
||||
};
|
||||
|
||||
if (modes[mode])
|
||||
modes[mode]();
|
||||
}
|
||||
|
||||
__HIGH_CODE
|
||||
@ -81,17 +93,19 @@ static void bm_transition()
|
||||
return;
|
||||
}
|
||||
}
|
||||
void play_splash(xbm_t *xbm, int col, int row)
|
||||
void play_splash(xbm_t *xbm, int col, int row, int spT)
|
||||
{
|
||||
while (ani_xbm_scrollup_pad(xbm, 11, 11, 11, fb, 0, 0) != 0) {
|
||||
DelayMs(30);
|
||||
DelayMs(spT);
|
||||
}
|
||||
}
|
||||
|
||||
void load_bmlist()
|
||||
{
|
||||
if (data_get_header(0) == 0) // There is no bitmap stored in flash
|
||||
return; // skip
|
||||
data_legacy_t header;
|
||||
data_get_header(&header);
|
||||
if (memcmp(header.header, "wang", 5))
|
||||
return; // There is no bitmap stored in flash
|
||||
|
||||
bm_t *curr_bm = bmlist_current();
|
||||
|
||||
@ -205,48 +219,18 @@ void ble_setup()
|
||||
tmos_clockInit();
|
||||
|
||||
peripheral_init();
|
||||
ble_disable_advertise();
|
||||
|
||||
if (! badge_cfg.ble_always_on) {
|
||||
ble_disable_advertise();
|
||||
}
|
||||
|
||||
devInfo_registerService();
|
||||
legacy_registerService();
|
||||
batt_registerService();
|
||||
ng_registerService();
|
||||
}
|
||||
|
||||
static void usb_receive(uint8_t *buf, uint16_t len)
|
||||
{
|
||||
static uint16_t rx_len, data_len;
|
||||
static uint8_t *data;
|
||||
|
||||
PRINT("dump first 8 bytes: %02x %02x %02x %02x %02x %02x %02x %02x\n",
|
||||
buf[0], buf[1], buf[2], buf[3],
|
||||
buf[4], buf[5], buf[6], buf[7]);
|
||||
|
||||
if (rx_len == 0) {
|
||||
if (memcmp(buf, "wang", 5))
|
||||
return;
|
||||
|
||||
int init_len = len > LEGACY_HEADER_SIZE ? len : sizeof(data_legacy_t);
|
||||
init_len += MAX_PACKET_SIZE;
|
||||
data = malloc(init_len);
|
||||
}
|
||||
|
||||
memcpy(data + rx_len, buf, len);
|
||||
rx_len += len;
|
||||
|
||||
if (!data_len) {
|
||||
data_legacy_t *d = (data_legacy_t *)data;
|
||||
uint16_t n = bigendian16_sum(d->sizes, 8);
|
||||
data_len = LEGACY_HEADER_SIZE + LED_ROWS * n;
|
||||
data = realloc(data, data_len);
|
||||
}
|
||||
|
||||
if ((rx_len > LEGACY_HEADER_SIZE) && rx_len >= data_len) {
|
||||
data_flatSave(data, data_len);
|
||||
SYS_ResetExecute();
|
||||
}
|
||||
}
|
||||
|
||||
void spawn_tasks()
|
||||
static void spawn_tasks()
|
||||
{
|
||||
common_taskid = TMOS_ProcessEventRegister(common_tasks);
|
||||
|
||||
@ -257,10 +241,8 @@ void spawn_tasks()
|
||||
tmos_start_task(common_taskid, ANI_NEXT_STEP, 500000 / 625);
|
||||
}
|
||||
|
||||
void ble_start()
|
||||
static void start_ble_animation()
|
||||
{
|
||||
ble_enable_advertise();
|
||||
|
||||
tmos_stop_task(common_taskid, ANI_NEXT_STEP);
|
||||
tmos_stop_task(common_taskid, ANI_MARQUE);
|
||||
tmos_stop_task(common_taskid, ANI_FLASH);
|
||||
@ -269,35 +251,54 @@ void ble_start()
|
||||
tmos_start_reload_task(common_taskid, BLE_NEXT_STEP, 500000 / 625);
|
||||
}
|
||||
|
||||
void handle_mode_transition()
|
||||
static void start_normal_animation()
|
||||
{
|
||||
static int prev_mode;
|
||||
if (prev_mode == mode) return;
|
||||
tmos_start_reload_task(common_taskid, ANI_MARQUE, ANI_MARQUE_SPEED_T / 625);
|
||||
tmos_start_reload_task(common_taskid, ANI_FLASH, ANI_FLASH_SPEED_T / 625);
|
||||
tmos_start_task(common_taskid, ANI_NEXT_STEP, 500000 / 625);
|
||||
tmos_stop_task(common_taskid, BLE_NEXT_STEP);
|
||||
}
|
||||
|
||||
switch (mode)
|
||||
{
|
||||
case DOWNLOAD:
|
||||
// Disable bitmap transition while in download mode
|
||||
btn_onOnePress(KEY2, NULL);
|
||||
|
||||
// Take control of the current bitmap to display
|
||||
// the Bluetooth animation
|
||||
ble_start();
|
||||
while (mode == DOWNLOAD) {
|
||||
TMOS_SystemProcess();
|
||||
}
|
||||
// If not being flashed, pressing KEY1 again will
|
||||
// make the badge goes off:
|
||||
|
||||
// fallthrough
|
||||
case POWER_OFF:
|
||||
poweroff();
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
static void resume_from_streaming()
|
||||
{
|
||||
if (badge_cfg.ble_always_on) {
|
||||
start_normal_animation();
|
||||
} else {
|
||||
start_ble_animation();
|
||||
}
|
||||
prev_mode = mode;
|
||||
}
|
||||
|
||||
static void stop_all_animation()
|
||||
{
|
||||
tmos_stop_task(common_taskid, ANI_NEXT_STEP);
|
||||
tmos_stop_task(common_taskid, ANI_MARQUE);
|
||||
tmos_stop_task(common_taskid, ANI_FLASH);
|
||||
tmos_stop_task(common_taskid, BLE_NEXT_STEP);
|
||||
memset(fb, 0, sizeof(fb));
|
||||
}
|
||||
|
||||
int streaming_enabled;
|
||||
|
||||
uint8_t streaming_setting(uint8_t *params, uint16_t len)
|
||||
{
|
||||
if (params[0] == 0x00) { // enter streaming mode
|
||||
stop_all_animation();
|
||||
streaming_enabled = 1;
|
||||
} else if (params[0] == 0x01) { // return to normal mode
|
||||
resume_from_streaming();
|
||||
streaming_enabled = 0;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint8_t stream_bitmap(uint8_t *params, uint16_t len)
|
||||
{
|
||||
if (! streaming_enabled) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
tmos_memcpy(fb, params, min(LED_COLS, len));
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void debug_init()
|
||||
@ -363,6 +364,51 @@ static void disp_charging()
|
||||
}
|
||||
}
|
||||
|
||||
static void mode_setup_download()
|
||||
{
|
||||
// If always-on BLE is enabled, then skip this mode, jump to next mode
|
||||
if (badge_cfg.ble_always_on) {
|
||||
change_mode();
|
||||
}
|
||||
|
||||
// Disable bitmap transition while in download mode
|
||||
btn_onOnePress(KEY2, NULL);
|
||||
|
||||
// Take control of the current bitmap to display
|
||||
// the Bluetooth animation
|
||||
ble_enable_advertise();
|
||||
start_ble_animation();
|
||||
}
|
||||
|
||||
void clean_bmlist()
|
||||
{
|
||||
bm_t *curr_bm = bmlist_current();
|
||||
while (curr_bm->next != curr_bm)
|
||||
bmlist_drop(curr_bm->next);
|
||||
}
|
||||
|
||||
void reload_bmlist()
|
||||
{
|
||||
clean_bmlist();
|
||||
load_bmlist();
|
||||
}
|
||||
|
||||
static void mode_setup_normal()
|
||||
{
|
||||
btn_onOnePress(KEY2, bm_transition);
|
||||
reload_bmlist();
|
||||
start_normal_animation();
|
||||
}
|
||||
|
||||
void handle_after_rx()
|
||||
{
|
||||
if (badge_cfg.reset_rx) {
|
||||
SYS_ResetExecute();
|
||||
} else {
|
||||
mode_setup_normal();
|
||||
}
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
SetSysClock(CLK_SOURCE_PLL_60MHz);
|
||||
@ -370,12 +416,12 @@ int main()
|
||||
debug_init();
|
||||
PRINT("\nDebug console is on UART%d\n", DEBUG);
|
||||
|
||||
cdc_onWrite(usb_receive);
|
||||
hiddev_onWrite(usb_receive);
|
||||
cdc_onWrite(legacy_usb_rx);
|
||||
hiddev_onWrite(legacy_usb_rx);
|
||||
usb_start();
|
||||
|
||||
led_init();
|
||||
TMR0_TimerInit(SCAN_T / 4);
|
||||
TMR0_TimerInit((FREQ_SYS / 2000) / 2);
|
||||
TMR0_ITCfg(ENABLE, TMR0_3_IT_CYC_END);
|
||||
PFIC_EnableIRQ(TMR0_IRQn);
|
||||
|
||||
@ -388,8 +434,14 @@ int main()
|
||||
|
||||
power_init();
|
||||
disp_charging();
|
||||
|
||||
play_splash(&splash, 0, 0);
|
||||
cfg_init();
|
||||
xbm_t spl = {
|
||||
.bits = &(badge_cfg.splash_bm_bits),
|
||||
.w = badge_cfg.splash_bm_w,
|
||||
.h = badge_cfg.splash_bm_h,
|
||||
.fh = badge_cfg.splash_bm_fh,
|
||||
};
|
||||
play_splash(&spl, 0, 0, badge_cfg.splash_speedT);
|
||||
|
||||
load_bmlist();
|
||||
|
||||
@ -399,7 +451,6 @@ int main()
|
||||
|
||||
mode = NORMAL;
|
||||
while (1) {
|
||||
handle_mode_transition();
|
||||
TMOS_SystemProcess();
|
||||
}
|
||||
}
|
||||
|
||||
161
src/ngctrl.c
Normal file
161
src/ngctrl.c
Normal file
@ -0,0 +1,161 @@
|
||||
#include "ngctrl.h"
|
||||
|
||||
#include "CH58xBLE_LIB.h"
|
||||
#include "CH583SFR.h"
|
||||
|
||||
#include "ble/profile.h"
|
||||
#include "power.h"
|
||||
#include "debug.h"
|
||||
#include "config.h"
|
||||
|
||||
// TODO: Some of configs can be added, just listing:
|
||||
// - Remote brighness adjusting
|
||||
// - Upload bitmap to ram
|
||||
|
||||
uint8_t next_packet(uint8_t *val, uint16_t len)
|
||||
{
|
||||
PRINT(__func__);
|
||||
PRINT(": to be implemented\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void cfg_reset_rx(uint8_t *state, uint16_t len)
|
||||
{
|
||||
badge_cfg.reset_rx = !!state[0];
|
||||
}
|
||||
|
||||
inline static void __poweroff(uint8_t *val, uint16_t len)
|
||||
{
|
||||
poweroff();
|
||||
}
|
||||
|
||||
inline static void __reset(uint8_t *val, uint16_t len)
|
||||
{
|
||||
SYS_ResetExecute();
|
||||
}
|
||||
|
||||
// Power off, reset after bitmap received.
|
||||
uint8_t power_setting(uint8_t *val, uint16_t len)
|
||||
{
|
||||
PRINT(__func__);
|
||||
PRINT("\n");
|
||||
|
||||
const void (*ble_lut[])(uint8_t *, uint16_t) = {
|
||||
__poweroff,
|
||||
cfg_reset_rx,
|
||||
__reset,
|
||||
};
|
||||
|
||||
uint8_t fn = val[0];
|
||||
if (fn >= (sizeof(ble_lut) / sizeof(ble_lut[0])))
|
||||
return -1;
|
||||
|
||||
ble_lut[fn](&val[1], len - 1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void cfg_ble_devname(uint8_t *name, uint16_t len)
|
||||
{
|
||||
tmos_memcpy(badge_cfg.ble_devname, name, len);
|
||||
}
|
||||
|
||||
static void cfg_ble_alwayon(uint8_t *val, uint16_t len)
|
||||
{
|
||||
badge_cfg.ble_always_on = val[0] != 0;
|
||||
}
|
||||
|
||||
/* always-on, adv name
|
||||
Screen off/on can be archived by entering/leaving streaming mode
|
||||
*/
|
||||
uint8_t ble_setting(uint8_t *val, uint16_t len)
|
||||
{
|
||||
PRINT(__func__);
|
||||
PRINT("\n");
|
||||
|
||||
const void (*ble_lut[])(uint8_t *, uint16_t) = {
|
||||
cfg_ble_alwayon,
|
||||
cfg_ble_devname
|
||||
};
|
||||
|
||||
uint8_t fn = val[0];
|
||||
if (fn >= (sizeof(ble_lut) / sizeof(ble_lut[0])))
|
||||
return -1;
|
||||
|
||||
ble_lut[fn](&val[1], len - 1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint8_t flash_splash_screen(uint8_t *val, uint16_t len)
|
||||
{
|
||||
PRINT(__func__);
|
||||
PRINT("\n");
|
||||
|
||||
uint8_t w = val[0];
|
||||
uint8_t h = val[1];
|
||||
uint8_t fh = val[2];
|
||||
uint8_t sz = len - 3;
|
||||
|
||||
if (w > SPLASH_MAX_WIDTH)
|
||||
return -1;
|
||||
if (h > SPLASH_MAX_HEIGHT)
|
||||
return -2;
|
||||
if (sz > SPLASH_MAX_SIZE)
|
||||
return -3;
|
||||
if (len < 3)
|
||||
return -4;
|
||||
|
||||
tmos_memcpy(badge_cfg.splash_bm_bits, &val[3], sz);
|
||||
badge_cfg.splash_bm_w = w;
|
||||
badge_cfg.splash_bm_h = h;
|
||||
badge_cfg.splash_bm_fh = fh;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint8_t save_cfg(uint8_t *val, uint16_t len)
|
||||
{
|
||||
PRINT(__func__);
|
||||
PRINT("\n");
|
||||
return (uint8_t)cfg_writeflash_def(&badge_cfg);
|
||||
}
|
||||
|
||||
uint8_t load_fallback_cfg(uint8_t *val, uint16_t len)
|
||||
{
|
||||
PRINT(__func__);
|
||||
PRINT("\n");
|
||||
cfg_fallback(&badge_cfg);
|
||||
return 0;
|
||||
}
|
||||
/* TODO: add a way to read configs */
|
||||
const uint8_t (*cmd_lut[])(uint8_t *val, uint16_t len) = {
|
||||
next_packet, // Unsure if we need this
|
||||
power_setting,
|
||||
streaming_setting,
|
||||
stream_bitmap,
|
||||
ble_setting,
|
||||
flash_splash_screen,
|
||||
save_cfg,
|
||||
load_fallback_cfg,
|
||||
};
|
||||
|
||||
#define CMD_LUT_LEN (sizeof(cmd_lut) / sizeof(cmd_lut[0]))
|
||||
|
||||
uint8_t ng_parse(uint8_t *val, uint16_t len)
|
||||
{
|
||||
uint8_t cmd = val[0];
|
||||
PRINT("LUT_LEN: %02x \n", CMD_LUT_LEN);
|
||||
if (cmd >= CMD_LUT_LEN) {
|
||||
PRINT("invalid command!\n");
|
||||
return bleInvalidRange;
|
||||
}
|
||||
|
||||
if (cmd_lut[cmd]) {
|
||||
PRINT("executing [cmd %02x] \n", cmd);
|
||||
uint8_t ret = (*cmd_lut[cmd])(val + 1, len - 1);
|
||||
ng_notify(&ret, 1); // response to the client app
|
||||
} else {
|
||||
PRINT("function is not defined!\n");
|
||||
}
|
||||
return SUCCESS;
|
||||
}
|
||||
20
src/ngctrl.h
Normal file
20
src/ngctrl.h
Normal file
@ -0,0 +1,20 @@
|
||||
#ifndef __NG_CTRL_H__
|
||||
#define __NG_CTRL_H__
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
// enum NG_STATUS {
|
||||
|
||||
// };
|
||||
|
||||
uint8_t next_packet(uint8_t *val, uint16_t len);
|
||||
uint8_t power_setting(uint8_t *val, uint16_t len);
|
||||
uint8_t ble_setting(uint8_t *val, uint16_t len);
|
||||
uint8_t streaming_setting(uint8_t *val, uint16_t len);
|
||||
uint8_t stream_bitmap(uint8_t *val, uint16_t len);
|
||||
uint8_t flash_splash_screen(uint8_t *val, uint16_t len);
|
||||
|
||||
extern const uint8_t (*cmd_lut[])(uint8_t *val, uint16_t len);
|
||||
uint8_t ng_parse(uint8_t *val, uint16_t len);
|
||||
|
||||
#endif /* __NG_CTRL_H__ */
|
||||
@ -1,7 +1,8 @@
|
||||
#include <CH58xBLE_LIB.h>
|
||||
#include <CH58x_common.h>
|
||||
|
||||
#include "power.h"
|
||||
#include "button.h"
|
||||
#include "debug.h"
|
||||
|
||||
void poweroff()
|
||||
{
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
#include "CH58x_common.h"
|
||||
#include "debug.h"
|
||||
|
||||
void print_setuppk(USB_SETUP_REQ *request)
|
||||
{
|
||||
|
||||
@ -1,14 +1,11 @@
|
||||
#ifndef __DEBUG_H__
|
||||
#define __DEBUG_H__
|
||||
#ifndef __USB_DEBUG_H__
|
||||
#define __USB_DEBUG_H__
|
||||
|
||||
#include "CH58x_common.h"
|
||||
|
||||
|
||||
#define _TRACE() PRINT("> "); PRINT(__FILE__);PRINT(": "); PRINT(__func__); \
|
||||
PRINT("()\n")
|
||||
#include "../debug.h"
|
||||
|
||||
void print_setuppk(USB_SETUP_REQ *setup_req_pk);
|
||||
void print_status_reg();
|
||||
void print_intflag_reg();
|
||||
|
||||
#endif /* __DEBUG_H__ */
|
||||
#endif /* __USB_DEBUG_H__ */
|
||||
|
||||
25
src/util/crc.c
Normal file
25
src/util/crc.c
Normal file
@ -0,0 +1,25 @@
|
||||
#include "crc.h"
|
||||
|
||||
// Polynomial: x^8 + x^2 + x + 1 (0xE0)
|
||||
uint8_t crc8_ccitt_update (uint8_t inCrc, uint8_t inData)
|
||||
{
|
||||
uint8_t data = inCrc ^ inData;
|
||||
for (int i = 0; i < 8; i++) {
|
||||
if (( data & 0x80 ) != 0 ) {
|
||||
data <<= 1;
|
||||
data ^= 0x07;
|
||||
} else {
|
||||
data <<= 1;
|
||||
}
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
uint8_t crc_cal(uint8_t *a, int len)
|
||||
{
|
||||
uint8_t crc = 0x00;
|
||||
for (int i=0; i<len; i++) {
|
||||
crc = crc8_ccitt_update(crc, a[i]);
|
||||
}
|
||||
return crc;
|
||||
}
|
||||
9
src/util/crc.h
Normal file
9
src/util/crc.h
Normal file
@ -0,0 +1,9 @@
|
||||
#ifndef __UTIL_CRC_H__
|
||||
#define __UTIL_CRC_H__
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
uint8_t crc8_ccitt_update (uint8_t inCrc, uint8_t inData);
|
||||
uint8_t crc_cal(uint8_t *a, int len);
|
||||
|
||||
#endif /* __UTIL_CRC_H__ */
|
||||
10
src/xbm.c
10
src/xbm.c
@ -2,15 +2,13 @@
|
||||
#include <stdlib.h>
|
||||
#include <memory.h>
|
||||
|
||||
#define ALIGNBIT(x) (((x % 8)>0)*8 + (x / 8) * 8)
|
||||
|
||||
/**
|
||||
* Draw bitmap file to fb at (col, row)
|
||||
* if bitmap file larger than fb, it will be stripped out
|
||||
*/
|
||||
void xbm2fb(xbm_t *xbm, uint16_t *fb, int col, int row)
|
||||
{
|
||||
int W = ALIGNBIT(xbm->w);
|
||||
int W = ALIGN_8BIT(xbm->w);
|
||||
uint16_t *tmpfb = malloc(W * sizeof(uint16_t));
|
||||
memset(tmpfb, 0, W * sizeof(uint16_t));
|
||||
|
||||
@ -32,7 +30,7 @@ void xbm2fb(xbm_t *xbm, uint16_t *fb, int col, int row)
|
||||
void xbm2fb_dirty(xbm_t *xbm, uint16_t *fb, int col, int row)
|
||||
{
|
||||
// Byte align for xbm bytes
|
||||
int W = ALIGNBIT(xbm->w);
|
||||
int W = ALIGN_8BIT(xbm->w);
|
||||
|
||||
for (int h = 0; h < xbm->h; h++) {
|
||||
for (int w = 0; w < W; w++) {
|
||||
@ -48,8 +46,8 @@ void xbm2fb_dirty(xbm_t *xbm, uint16_t *fb, int col, int row)
|
||||
*/
|
||||
xbm_t *xbm_croph(xbm_t *xbm, xbm_t *frame, int from_row, int to_row)
|
||||
{
|
||||
int rb = xbm->w / 8 + ((xbm->w % 8)>0); // Number of bytes in a row
|
||||
if (to_row * rb > rb * xbm->h)
|
||||
int rb = ALIGN_1BYTE(xbm->w); // Number of bytes in a row
|
||||
if (to_row > xbm->h)
|
||||
return NULL;
|
||||
|
||||
frame->bits = &xbm->bits[rb * from_row];
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user