mirror of
https://github.com/tpunix/HMCLOCK.git
synced 2025-12-06 08:12:48 +08:00
初步实现OTA功能
This commit is contained in:
@@ -7,7 +7,7 @@
|
||||
显示农历与节气和节假日
|
||||
显示电池电量
|
||||
蓝牙对时
|
||||
蓝牙OTA(尚未实现)
|
||||
蓝牙OTA
|
||||
|
||||
|
||||
编译与烧写
|
||||
|
||||
@@ -55,7 +55,7 @@
|
||||
****************************************************************************************
|
||||
*/
|
||||
|
||||
#define EPD_VERSION 0xA50f0004
|
||||
#define EPD_VERSION 0xA50f0005
|
||||
|
||||
|
||||
/*
|
||||
@@ -231,7 +231,7 @@ static const struct gapm_configuration user_gapm_conf = {
|
||||
|
||||
/// Maximal MTU. Shall be set to 23 if Legacy Pairing is used, 65 if Secure Connection is used,
|
||||
/// more if required by the application
|
||||
.max_mtu = 23,
|
||||
.max_mtu = 192,
|
||||
|
||||
/// Device Address Type
|
||||
.addr_type = APP_CFG_ADDR_TYPE(USER_CFG_ADDRESS_MODE),
|
||||
|
||||
@@ -59,7 +59,7 @@
|
||||
// Service 1 of the custom server 1
|
||||
#define DEF_SVC1_CTRL_POINT_CHAR_LEN 1
|
||||
#define DEF_SVC1_ADC_VAL_1_CHAR_LEN 2
|
||||
#define DEF_SVC1_LONG_VALUE_CHAR_LEN 48
|
||||
#define DEF_SVC1_LONG_VALUE_CHAR_LEN 160
|
||||
|
||||
|
||||
/// Custom1 Service Data Base Characteristic enum
|
||||
|
||||
@@ -26,6 +26,7 @@ int sf_sector_erase(int cmd, int addr, int wait);
|
||||
int sf_page_write(int addr, u8 *buf, int size);
|
||||
int sf_read(int addr, int len, u8 *buf);
|
||||
int selflash(int otp_boot);
|
||||
int ota_handle(u8 *buf);
|
||||
|
||||
// epd_hw
|
||||
void epd_hw_init(u32 config0, u32 config1, int w, int h, int mode);
|
||||
|
||||
@@ -514,6 +514,10 @@ void clock_draw(int flags)
|
||||
{
|
||||
char tbuf[64];
|
||||
|
||||
if(ota_state){
|
||||
return;
|
||||
}
|
||||
|
||||
epd_hw_open();
|
||||
|
||||
epd_update_mode(flags&3);
|
||||
@@ -571,14 +575,17 @@ void user_svc1_ctrl_wr_ind_handler(ke_msg_id_t const msgid, struct custs1_val_wr
|
||||
|
||||
void user_svc1_long_val_wr_ind_handler(ke_msg_id_t const msgid, struct custs1_val_write_ind const *param, ke_task_id_t const dest_id, ke_task_id_t const src_id)
|
||||
{
|
||||
printk("Long value: %d\n", param->length);
|
||||
//printk("Long value: %d\n", param->length);
|
||||
if(param->value[0]==0x91){
|
||||
clock_set((uint8_t*)param->value);
|
||||
clock_draw(DRAW_BT|UPDATE_FAST);
|
||||
clock_print();
|
||||
}else if(param->value[0]>=0xa0){
|
||||
ota_handle((u8*)param->value);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void user_svc1_long_val_att_info_req_handler(ke_msg_id_t const msgid, struct custs1_att_info_req const *param, ke_task_id_t const dest_id, ke_task_id_t const src_id)
|
||||
{
|
||||
struct custs1_att_info_rsp *rsp = KE_MSG_ALLOC(CUSTS1_ATT_INFO_RSP, src_id, dest_id, custs1_att_info_rsp);
|
||||
|
||||
@@ -77,6 +77,8 @@ static char adv_name[20];
|
||||
char *bt_id = adv_name+12;
|
||||
int clock_interval;
|
||||
|
||||
const volatile u32 epd_version[3] = {0xF9A51379, ~0xF9A51379, EPD_VERSION};
|
||||
|
||||
|
||||
/*
|
||||
* FUNCTION DEFINITIONS
|
||||
@@ -173,7 +175,7 @@ void user_app_init(void)
|
||||
{
|
||||
read_otp_value();
|
||||
|
||||
printk("\n\nuser_app_init! %s\n", __TIME__);
|
||||
printk("\n\nuser_app_init! %s %08x\n", __TIME__, epd_version[2]);
|
||||
app_param_update_request_timer_used = EASY_TIMER_INVALID_TIMER;
|
||||
app_clock_timer_used = EASY_TIMER_INVALID_TIMER;
|
||||
|
||||
@@ -240,6 +242,8 @@ void user_app_on_db_init_complete( void )
|
||||
|
||||
void user_app_adv_start(void)
|
||||
{
|
||||
u8 vbuf[4];
|
||||
|
||||
if(adv_state)
|
||||
return;
|
||||
adv_state = 1;
|
||||
@@ -247,6 +251,13 @@ void user_app_adv_start(void)
|
||||
struct gapm_start_advertise_cmd* cmd = app_easy_gap_undirected_advertise_get_active();
|
||||
app_add_ad_struct(cmd, adv_name, adv_name[0]+1, 1);
|
||||
|
||||
vbuf[0] = 0x03;
|
||||
vbuf[1] = GAP_AD_TYPE_MANU_SPECIFIC_DATA;
|
||||
vbuf[2] = EPD_VERSION&0xff;
|
||||
vbuf[3] = (EPD_VERSION>>8)&0xff;
|
||||
app_add_ad_struct(cmd, vbuf, vbuf[0]+1, 1);
|
||||
|
||||
|
||||
//default_advertise_operation();
|
||||
//app_easy_gap_undirected_advertise_start();
|
||||
app_easy_gap_undirected_advertise_with_timeout_start(user_default_hnd_conf.advertise_period, NULL);
|
||||
@@ -327,7 +338,7 @@ void user_catch_rest_hndl(ke_msg_id_t const msgid,
|
||||
case CUSTS1_VAL_WRITE_IND:
|
||||
{
|
||||
/* 写特征值通知. 值已经写入Database中了. */
|
||||
printk("CUSTS1_VAL_WRITE_IND!\n");
|
||||
//printk("CUSTS1_VAL_WRITE_IND!\n");
|
||||
struct custs1_val_write_ind const *msg_param = (struct custs1_val_write_ind const *)(param);
|
||||
|
||||
switch (msg_param->handle)
|
||||
@@ -358,7 +369,7 @@ void user_catch_rest_hndl(ke_msg_id_t const msgid,
|
||||
case CUSTS1_ATT_INFO_REQ:
|
||||
{
|
||||
/* 读ATT_INFO请求. 需要返回数据. */
|
||||
printk("CUSTS1_ATT_INFO_REQ!\n");
|
||||
//printk("CUSTS1_ATT_INFO_REQ!\n");
|
||||
struct custs1_att_info_req const *msg_param = (struct custs1_att_info_req const *)param;
|
||||
|
||||
switch (msg_param->att_idx)
|
||||
|
||||
@@ -86,6 +86,7 @@
|
||||
*/
|
||||
|
||||
extern char *bt_id;
|
||||
extern int ota_state;
|
||||
|
||||
|
||||
/*
|
||||
|
||||
131
weble/weble.html
131
weble/weble.html
@@ -13,8 +13,10 @@
|
||||
<div id="current_voltage"></div>
|
||||
<div id="current_time"></div>
|
||||
<div id="system_time"></div>
|
||||
<div id="update_progress"></div>
|
||||
|
||||
<script src="log.js"></script>
|
||||
<script src="https://cdn.sheetjs.com/crc-32-latest/package/crc32.js"></script>
|
||||
|
||||
<script>
|
||||
var connected = false;
|
||||
@@ -87,6 +89,7 @@
|
||||
|
||||
connected = true;
|
||||
document.getElementById('setime-button').disabled = false;
|
||||
document.getElementById('upfirm-button').disabled = false;
|
||||
document.getElementById('connect-button').textContent = "断开";
|
||||
} catch (error) {
|
||||
console.log('连接失败:', error);
|
||||
@@ -94,6 +97,9 @@
|
||||
}
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
async function onSetTime() {
|
||||
document.getElementById('setime-button').disabled = true;
|
||||
|
||||
@@ -139,6 +145,130 @@
|
||||
document.getElementById('setime-button').disabled = false;
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
function readFileAsArrayBuffer(file) {
|
||||
return new Promise((resolve, reject) => {
|
||||
const reader = new FileReader();
|
||||
reader.onload = () => resolve(reader.result);
|
||||
reader.onerror = reject;
|
||||
reader.readAsArrayBuffer(file);
|
||||
});
|
||||
}
|
||||
|
||||
function find_patten(target, patten) {
|
||||
tlen = target.length;
|
||||
plen = patten.length;
|
||||
for(i=0; i<tlen-plen; i++){
|
||||
for(j=0; j<plen; j++){
|
||||
if(target[i+j] !== patten[j]){
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(j==plen)
|
||||
return i;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
async function onUpdate() {
|
||||
document.getElementById('upfirm-button').disabled = true;
|
||||
var firm_size;
|
||||
var firm_buf;
|
||||
|
||||
try{
|
||||
console.log('准备打开文件');
|
||||
const file_handle = await window.showOpenFilePicker({
|
||||
types: [{
|
||||
description: 'Firm files',
|
||||
accept: {
|
||||
'text/plain': ['.bin'],
|
||||
},
|
||||
}]
|
||||
});
|
||||
console.log('选择文件: ', file_handle);
|
||||
const file = await file_handle[0].getFile();
|
||||
console.log('file: ', file);
|
||||
|
||||
abuf = await readFileAsArrayBuffer(file);
|
||||
firm_buf = new Uint8Array(abuf);
|
||||
firm_size = file.size;
|
||||
}catch(err){
|
||||
console.log('文件读取失败: ', err);
|
||||
document.getElementById('upfirm-button').disabled = false;
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
firm_magic = new Uint8Array([0x79, 0x13, 0xa5, 0xf9, 0x86, 0xec, 0x5a, 0x06]);
|
||||
pos = find_patten(firm_buf, firm_magic);
|
||||
if(pos == -1) {
|
||||
console.log('无效固件: 未找到版本号!');
|
||||
document.getElementById('upfirm-button').disabled = false;
|
||||
return;
|
||||
}
|
||||
firm_ver = firm_buf[pos+9]*256+firm_buf[pos+8];
|
||||
console.log('固件版本:', firm_ver);
|
||||
console.log('固件大小:', firm_size);
|
||||
|
||||
firm_crc = CRC32.buf(firm_buf);
|
||||
console.log('固件CRC:', (firm_crc >>> 0).toString(16));
|
||||
|
||||
var buf = new Uint8Array(136);
|
||||
dataView = new DataView(buf.buffer);
|
||||
|
||||
console.log('开始升级');
|
||||
buf[0] = 0xa0;
|
||||
buf[1] = 0x00;
|
||||
dataView.setUint16(2, firm_size, true);
|
||||
await longValue.writeValue(buf);
|
||||
|
||||
var pos = 0;
|
||||
for(i=0; i<firm_size+64; i+=256){
|
||||
console.log('发送', i);
|
||||
buf.fill(0xff);
|
||||
if(i==0){
|
||||
dataView.setUint32(8+0, 0x00aa5170, true);
|
||||
dataView.setUint32(8+4, firm_size, true);
|
||||
dataView.setUint32(8+8, firm_crc, true);
|
||||
dataView.setUint32(8+28, (0xa50f0000+firm_ver), true);
|
||||
buf[8+32] = 0;
|
||||
buf[0] = 0xa2;
|
||||
buf.set(firm_buf.subarray(pos, pos+64), 8+64);
|
||||
await longValue.writeValue(buf);
|
||||
pos += 64;
|
||||
}else{
|
||||
buf[0] = 0xa2;
|
||||
buf.set(firm_buf.subarray(pos, pos+128), 8);
|
||||
await longValue.writeValue(buf);
|
||||
pos += 128;
|
||||
}
|
||||
|
||||
buf[0] = 0xa3;
|
||||
buf.set(firm_buf.subarray(pos, pos+128), 8);
|
||||
await longValue.writeValue(buf);
|
||||
pos += 128;
|
||||
document.getElementById('update_progress').textContent =
|
||||
'升级进度: '+((100*pos/(firm_size+64))>>0)+'%';
|
||||
}
|
||||
console.log('发送完毕');
|
||||
|
||||
buf[0] = 0xa4;
|
||||
buf[1] = 0x00;
|
||||
buf[2] = 0x00;
|
||||
buf[3] = 0x00;
|
||||
await longValue.writeValue(buf);
|
||||
console.log('升级结束');
|
||||
|
||||
document.getElementById('upfirm-button').disabled = false;
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
function disconnect() {
|
||||
document.getElementById('setime-button').disabled = true;
|
||||
if(!device)
|
||||
@@ -159,6 +289,7 @@
|
||||
|
||||
document.getElementById('connect-button').addEventListener('click', onClick);
|
||||
document.getElementById('setime-button').addEventListener('click', onSetTime);
|
||||
document.getElementById('upfirm-button').addEventListener('click', onUpdate);
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
Reference in New Issue
Block a user