add set SERVICES

This commit is contained in:
pvvx 2024-01-21 18:54:48 +03:00
parent 91be666ec3
commit d767a5c4ac
14 changed files with 4650 additions and 5166 deletions

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -58,6 +58,8 @@ typedef struct _ota_par_t {
uint32_t erase_addr;
} ota_par_t;
#define OTA_MODE_SELECT_REG 0x4000f034 // == 0x55 -> OTA
extern ota_par_t ota;
int ota_parser(unsigned char *pout, unsigned char *pmsg, unsigned int msg_size);

View file

@ -17,15 +17,27 @@
#include "gatt_uuid.h"
#include "gattservapp.h"
#include "gapbondmgr.h"
#include "flash.h"
#include "flash_eep.h"
#include "bleperipheral.h"
#include "sbp_profile.h"
#include "sensor.h"
#include "cmd_parcer.h"
#include "devinfoservice.h"
#include "ble_ota.h"
#include "thb2_peripheral.h"
/*********************************************************************/
#define SEND_DATA_SIZE 16
const dev_id_t dev_id = {
.pid = CMD_ID_DEVID,
.revision = 1,
.hw_version = DEVICE,
.sw_version = APP_VERSION,
.dev_spec_data = 0,
.services = DEV_SERVICES
};
int cmd_parser(uint8_t * obuf, uint8_t * ibuf, uint32_t len) {
int olen = 0;
if (len) {
@ -33,14 +45,8 @@ int cmd_parser(uint8_t * obuf, uint8_t * ibuf, uint32_t len) {
obuf[0] = cmd;
obuf[1] = 0; // no err
if (cmd == CMD_ID_DEVID) { // Get DEV_ID
pdev_id_t p = (pdev_id_t) obuf;
// p->pid = CMD_ID_DEV_ID;
p->revision = 1;
p->hw_version = DEVICE;
p->sw_version = APP_VERSION;
p->dev_spec_data = 0;
p->services = 0;
olen = sizeof(dev_id_t);
osal_memcpy(obuf, &dev_id, sizeof(dev_id));
olen = sizeof(dev_id);
} else if (cmd == CMD_ID_CFG) { // Get/Set device config
if (--len > sizeof(cfg))
len = sizeof(cfg);
@ -71,6 +77,29 @@ int cmd_parser(uint8_t * obuf, uint8_t * ibuf, uint32_t len) {
init_sensor();
osal_memcpy(&obuf[1], &thsensor_cfg, thsensor_cfg_size);
olen = thsensor_cfg_size + 1;
} else if (cmd == CMD_ID_SERIAL) {
osal_memcpy(&obuf[1], devInfoSerialNumber, sizeof(devInfoSerialNumber)-1);
olen = 1 + sizeof(devInfoSerialNumber)-1;
} else if (cmd == CMD_ID_FLASH_ID) {
osal_memcpy(&obuf[1], (uint8_t *)&phy_flash.IdentificationID, 8);
olen = 1 + 8;
} else if (cmd == CMD_ID_SEN_ID) {
osal_memcpy(&obuf[1], (uint8_t *)&thsensor_cfg.mid, 5);
olen = 1 + 5;
// } else if (cmd == CMD_ID_DNAME) {
// } else if (cmd == CMD_ID_DEV_MAC) {
} else if (cmd == CMD_ID_MTU) {
if (ibuf[1] >= MTU_SIZE)
ATT_UpdateMtuSize(gapRole_ConnectionHandle, ibuf[1]);
else
obuf[1] = 0xff;
olen = 2;
} else if (cmd == CMD_ID_REBOOT) {
GAPRole_TerminateConnection();
if(len >= 2) {
write_reg(OTA_MODE_SELECT_REG, ibuf[1]);
}
hal_system_soft_reset();
//---------- Debug commands (unsupported in different versions!):

View file

@ -26,6 +26,7 @@ enum CMD_ID_KEYS {
CMD_ID_I2C_UTR = 0x04, // Universal I2C/SMBUS read-write
CMD_ID_SEN_ID = 0x05, // Get sensor ID
CMD_ID_FLASH_ID = 0x06, // Get Flash JEDEC ID
CMD_ID_SERIAL = 0x07, // Get serial string
CMD_ID_DEV_MAC = 0x10, // Get/Set MAC [+RandMAC], [size][mac[6][randmac[2]]]
CMD_ID_BKEY = 0x18, // Get/Set beacon bindkey in EEP
CMD_ID_COMFORT = 0x20, // Get/Set comfort parameters
@ -50,6 +51,7 @@ enum CMD_ID_KEYS {
CMD_ID_REBOOT = 0x72, // Set Reboot on disconnect
CMD_ID_SET_OTA = 0x73, // Extension BigOTA: Get/set address and size OTA, erase sectors
// Debug commands (unsupported in different versions!):
CMD_ID_OTAC = 0xD1, // OTA clear
@ -65,6 +67,23 @@ enum CMD_ID_KEYS {
};
// supported services by the device
typedef struct _dev_services_t{
uint32_t ota: 1; //0 OTA
uint32_t ota_ext: 1; //1 OTA extension
uint32_t pincode: 1; //2 pin-code
uint32_t bindkey: 1; //3 bindkey
uint32_t history: 1; //4 history
uint32_t screen: 1; //5 screen
uint32_t long_range: 1; //6 LE Long Range
uint32_t ths: 1; //7 T & H sensor
uint32_t rds: 1; //8 Reed switch sensor
uint32_t key: 1; //9 key
uint32_t out_pins: 1; //10 Output pins
uint32_t inp_pins: 1; //11 Input pins
uint32_t reserved: 20;
} dev_services_t;
// CMD_ID_DEV_ID
typedef struct _dev_id_t{
@ -76,6 +95,8 @@ typedef struct _dev_id_t{
uint32_t services; // supported services by the device
} dev_id_t, * pdev_id_t;
extern const dev_id_t dev_id;
int cmd_parser(uint8_t * obuf, uint8_t * ibuf, uint32_t len);
#ifdef __cplusplus

View file

@ -13,6 +13,7 @@
#ifndef APP_VERSION
#define APP_VERSION 0x06 // BCD
#endif
/*
#define BOARD_LYWSD03MMC_B14 0 // number used for BLE firmware
#define BOARD_MHO_C401 1
@ -40,9 +41,23 @@
#define DEVICE DEVICE_BTH01
#endif
// supported services by the device (bits)
#define SERVICE_OTA 0x0001
#define SERVICE_OTA_EXT 0x0002
#define SERVICE_PINCODE 0x0004 // пока нет
#define SERVICE_BINDKEY 0x0008 // пока нет
#define SERVICE_HISTORY 0x0010 // пока нет
#define SERVICE_SCREEN 0x0020 // пока нет
#define SERVICE_LE_LR 0x0040 // пока нет
#define SERVICE_THS 0x0080
#define SERVICE_RDS 0x0100 // пока нет
#define SERVICE_KEY 0x0200
#define SERVICE_OUTS 0x0400 // пока нет
#define SERVICE_INS 0x0800 // пока нет
#define OTA_TYPE_NONE 0 // нет OTA
#define OTA_TYPE_BOOT 1 // вариант для прошивки boot + OTA
#define OTA_TYPE_APP 2 // переключение из APP на OTA + boot прошивку, пока не реализовано
#define OTA_TYPE_BOOT (SERVICE_OTA | SERVICE_OTA_EXT) // вариант для прошивки boot + OTA
#define OTA_TYPE_APP SERVICE_OTA_EXT // переключение из APP на OTA + boot прошивку, пока не реализовано
#ifndef OTA_TYPE
#define OTA_TYPE OTA_TYPE_BOOT
@ -52,6 +67,12 @@
#if DEVICE == DEVICE_THB2
/* Model: THB2 */
#define DEV_SERVICES (OTA_TYPE \
| SERVICE_THS \
| SERVICE_KEY \
)
#define ADC_PIN_USE_OUT 0
#define ADC_PIN GPIO_P11
#define ADC_CHL ADC_CH1N_P11
@ -69,6 +90,10 @@
#elif DEVICE == DEVICE_BTH01
/* Model: BTH01 */
#define DEV_SERVICES (OTA_TYPE \
| SERVICE_THS \
| SERVICE_KEY \
)
#define ADC_PIN_USE_OUT 1 // hal_gpio_write(ADC_PIN, 1);
#define ADC_PIN GPIO_P11
@ -89,10 +114,20 @@
#elif DEVICE == DEVICE_TH05
/* Model: TH05 */
#define DEV_SERVICES (OTA_TYPE \
| SERVICE_THS \
| SERVICE_KEY \
| SERVICE_SCREEN \
)
#define ADC_PIN_USE_OUT 1 // hal_gpio_write(ADC_PIN, 1);
#define ADC_PIN GPIO_P11
#define ADC_CHL ADC_CH1N_P11
#define USE_TH_SENSOR 1
#define USE_RS_SENSOR 0
#define USE_SECREEN 1
#define I2C_SDA GPIO_P33 // CHT8305_SDA
#define I2C_SCL GPIO_P34 // CHT8305_SCL
#define GPIO_SPWR GPIO_P00 // питание сенсора CHT8305_VDD
@ -109,8 +144,6 @@
#error "DEVICE Not released!"
#endif
#define OTA_MODE_SELECT_REG 0x4000f034 // == 0x55 -> OTA
// Minimum connection interval (units of 1.25ms, 80=100ms) if automatic parameter update request is enabled
#define DEFAULT_DESIRED_MIN_CONN_INTERVAL 24 // 12 -> 15 ms
// Maximum connection interval (units of 1.25ms, 800=1000ms) if automatic parameter update request is enabled

View file

@ -156,7 +156,7 @@ const uint8 devInfoModelNumber[] = DEF_MODEL_NUMBER_STR;
#if SERIAL_NUMBER_STR_ENABLE
// Serial Number String characteristic
static uint8 devInfoSerialNumberProps = GATT_PROP_READ;
uint8 devInfoSerialNumber[21]; // = "000000-00000000-0000"; // FLASH_ID-SENSOR_ID-EFUSE
uint8 devInfoSerialNumber[19]; // = "000000-00000000-00"; // FLASH_ID-SENSOR_ID-EFUSE
#endif
#if FIRMWARE_REVISION_ENABLE

View file

@ -99,7 +99,7 @@ bStatus_t DevInfo_SetParameter( uint8 param, uint8 len, void* value );
extern bStatus_t DevInfo_GetParameter( uint8 param, void* value );
extern uint8 devInfoSerialNumber[21];
extern uint8 devInfoSerialNumber[19];
extern const uint8 devInfoModelNumber[];
/*********************************************************************
*********************************************************************/

View file

@ -35,27 +35,29 @@
/*********************************************************************
* TYPEDEFS
*/
#define SERVICE_BTHOME_UUID16 0xFCD2 // 16-bit UUID Service 0xFCD2 BTHOME
#define CHARACTERISTIC_OTA_UUID16 0xFFF3
#define CHARACTERISTIC_CMD_UUID16 0xFFF4
/*********************************************************************
* GLOBAL VARIABLES
*/
// Simple GATT Profile Service UUID: 0xFFF0
// Simple GATT Profile Service UUID: 0xFCD2
CONST uint8_t simpleProfileServUUID[ATT_BT_UUID_SIZE] =
{
LO_UINT16(SIMPLEPROFILE_SERV_UUID), HI_UINT16(SIMPLEPROFILE_SERV_UUID)
LO_UINT16(SERVICE_BTHOME_UUID16), HI_UINT16(SERVICE_BTHOME_UUID16)
};
#if OTA_TYPE
// Characteristic 1 UUID: 0xFFF3
// Characteristic 1 UUID: 0x0001
CONST uint8_t simpleProfilechar1UUID[ATT_BT_UUID_SIZE] =
{
LO_UINT16(SIMPLEPROFILE_CHAR1_UUID), HI_UINT16(SIMPLEPROFILE_CHAR1_UUID)
LO_UINT16(CHARACTERISTIC_OTA_UUID16), HI_UINT16(CHARACTERISTIC_OTA_UUID16)
};
#endif
// Characteristic 2 UUID: 0xFFF4
// Characteristic 2 UUID: 0x0002
CONST uint8_t simpleProfilechar2UUID[ATT_BT_UUID_SIZE] =
{
LO_UINT16(SIMPLEPROFILE_CHAR2_UUID), HI_UINT16(SIMPLEPROFILE_CHAR2_UUID)
LO_UINT16(CHARACTERISTIC_CMD_UUID16), HI_UINT16(CHARACTERISTIC_CMD_UUID16)
};
/*********************************************************************
@ -310,8 +312,8 @@ static bStatus_t simpleProfile_ReadAttrCB( uint16_t connHandle, gattAttribute_t
break;
#endif
case SIMPLEPROFILE_CHAR2_UUID:
*pLen = sizeof(cfg);
osal_memcpy( pValue, &cfg, *pLen );
*pLen = sizeof(dev_id);
osal_memcpy( pValue, &dev_id, *pLen);
LOG("Read_UUID2:\n");
break;
default:

View file

@ -109,12 +109,9 @@ struct __attribute__((packed)) _cht8305_config_t{
#define CHT8305_ID 0x5959
/*
---------------------------------------
/*---------------------------------------
Датчик влажности AHT25
---------------------------------------
*/
---------------------------------------*/
#define AHT30_I2C_ADDR 0x38
#define AHT30_CMD_INI 0x0E1 // Initialization Command

View file

@ -140,27 +140,15 @@ static void set_mac(void)
set_def_name(ownPublicAddr);
}
typedef enum
{
EFUSE_BLOCK_0 = 0,
EFUSE_BLOCK_1 = 1,
EFUSE_BLOCK_2 = 2,
EFUSE_BLOCK_3 = 3,
} EFUSE_block_t;
extern int efuse_read(EFUSE_block_t block,uint32_t* buf);
static void set_serial_number(void)
{
hal_get_flash_info();
uint32_t temp_rd[2] = {0, 0};
efuse_read(EFUSE_BLOCK_0, temp_rd);
uint8_t *p = str_bin2hex(devInfoSerialNumber, (uint8_t *)&phy_flash.IdentificationID, 3);
*p++ = '-';
p = str_bin2hex(p, (uint8_t *)&thsensor_cfg.mid, 4);
*p++ = '-';
p = str_bin2hex(p, (uint8_t *)&temp_rd[0], 2);
*p++ = '0';
*p = '0';
}
extern gapPeriConnectParams_t periConnParameters;

View file

@ -10,6 +10,7 @@ const FLASH_SIZE = 0x80000;
var bluetoothDevice, gattServer, otaCharacteristic, cmdCharacteristic, infoService;
var devinfo = {};
var devsrs = {};
var startTime = 0,
connected = false;
@ -57,8 +58,8 @@ function handleError(text) {
function connect() {
var deviceOptions = {
optionalServices: [0x1800, 0x180a, 0x180f, 0x181a, 0xfff0, 0x2a26],
services: [0x1800, 0x180a, 0x180f, 0x181a, 0xfff0, 0x2a26],
optionalServices: [0x1800, 0x180a, 0x180f, 0x181a, 0xfcd2],
services: [0x1800, 0x180a, 0x180f, 0x181a, 0xfcd2],
acceptAllDevices: true };
const namePrefix = $('inpNamePrefix').value;
if (namePrefix) {
@ -154,7 +155,7 @@ function linkOta() {
}).then(_ => {
return otaCharacteristic.readValue();
}).then(value => {
if(value.byteLength >= 20)
if(value.byteLength > 1)
addLog("OTA ver: "+ hex(value.getUint8(1),2));
return resolve(null);});
}).catch(error => { console.log(error); return resolve(null);});
@ -172,7 +173,7 @@ function phyConnect(info_flg) {
addLog("Hardware: "+devinfo.hrstr);
if(devinfo.vrstr != null)
addLog("Software: "+devinfo.vrstr);
return gattServer.getPrimaryService(0xfff0);
return gattServer.getPrimaryService(0xfcd2);
}).then(service => {
console.log("Найден Main Service");
mainService = service;
@ -187,7 +188,8 @@ function phyConnect(info_flg) {
return cmdCharacteristic.readValue();
}).then(value => {
if(value.byteLength >= 10)
addLog("DevCfg: 55"+dump8(value, value.byteLength));
if(value.getUint8(0) == 0)
addLog("Device id: "+hex(value.getUint16(2, true)),4);
otaCharacteristic = null;
return linkOta();
}).then(_ => {
@ -216,7 +218,7 @@ function doConnect() {
console.log("Services: " + services[i].uuid);
if (services[i].uuid == "0000180a-0000-1000-8000-00805f9b34fb")
info = true;
else if (services[i].uuid == "0000fff0-0000-1000-8000-00805f9b34fb")
else if (services[i].uuid == "0000fcd2-0000-1000-8000-00805f9b34fb")
phy = true;
}
if(phy)
@ -351,9 +353,7 @@ function crc16_modbus(buffer) {
for (var j = 0; j < 8; j++) {
odd = crc & 0x0001;
crc = crc >> 1;
if (odd) {
crc = crc ^ 0xA001;
}
if (odd) crc = crc ^ 0xA001;
}
}
return crc;

View file

@ -1,601 +0,0 @@
<html class="telFlasherClass"><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>PHY62x2-BTHome тест версия</title>
</head>
<body>
<script>
//BLE values
const FLASH_SIZE = 0x80000;
var bluetoothDevice, gattServer, otaCharacteristic, myCharacteristic;
//Firmware values
var firmwareArray = null,
startTime = 0,
flgRdFF = false,
fwmaxsize = 196608,
fwname = "",
blockCount = 0;
//Connection values
var connectTrys = 0;
var $ = function(id) { return document.getElementById(id);}
function resetVariables() {
busy = false;
gattServer = null;
Theservice = null;
otaCharacteristic = null;
myCharacteristic = null;
$('butReadAddr').disabled = true;
$('butStartDFU').disabled = true;
$('butWriteData').disabled = true;
$('butCmdData').disabled = true;
}
function handleError(error) {
addLog(error);
resetVariables();
if (connectTrys < 5) {
connectTrys++;
addLog("Переподключение " + connectTrys + " из " + 5);
doConnect();
} else {
addLog("Подключится не удалось!");
connectTrys = 0;
}
}
function onDisconnected() {
addLog('Disconnected.');
}
function connect() {
var deviceOptions = {
optionalServices: [0xfff0],
services: [0x180a, 0x181c, 0x181e, 0xfff0],
acceptAllDevices: true };
const namePrefix = $('namePrefix').value;
if (namePrefix) {
deviceOptions.acceptAllDevices = false;
deviceOptions.filters = namePrefix.split(",")
.map((x) => ({ namePrefix: x }));
} else {
deviceOptions.acceptAllDevices = false;
deviceOptions.filters = "ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz_#@!*0123456789';,.<>{}[]"
.split("")
.map((x) => ({ namePrefix: x }));
}
if (bluetoothDevice != null) bluetoothDevice.gatt.disconnect();
resetVariables();
addLog("Поиск устройств");
connectTrys = 0;
navigator.bluetooth.requestDevice(deviceOptions).then(device => {
bluetoothDevice = device;
bluetoothDevice.addEventListener('gattserverdisconnected', onDisconnected);
addLog("Connecting to: " + bluetoothDevice.name);
doConnect();
}).catch(handleError);
}
function doConnect() {
bluetoothDevice.gatt.connect().then(server => {
addClog("Найден GATT сервер");
gattServer = server;
return gattServer.getPrimaryService(0xfff0);
}).then(service => {
addClog("Найден Main сервис");
Theservice = service;
return service.getCharacteristic(0xfff3);
}).then(characteristic => {
addClog("Найдена OTA характеристика");
otaCharacteristic = characteristic;
return otaCharacteristic.addEventListener('characteristicvaluechanged', event => OtaBlkParse(event.target.value));
}).then(_ => {
return otaCharacteristic.readValue();
}).then(value => {
if(value.byteLength >= 20)
addLog("OTA: "+dump8(value, value.byteLength));
return Theservice.getCharacteristic(0xfff4);
}).then(characteristic => {
addClog("Найдена CMD характеристика");
myCharacteristic = characteristic;
return myCharacteristic.readValue();
}).then(value => {
if(value.byteLength >= 10)
addLog("DevCfg: "+dump8(value, value.byteLength));
return myCharacteristic.addEventListener('characteristicvaluechanged', event => CustomBlkParse(event.target.value));
}).then(_ => {
myCharacteristic.startNotifications().then(_ => {
let s = "Устройство подключено.";
addAlog(s);
$('butCmdData').disabled = false;
$('butReadAddr').disabled = false;
$('butWriteData').disabled = false;
if (firmwareArray != null) $('butStartDFU').disabled = false;
})
}).catch(handleError);
}
function reConnect() {
if (bluetoothDevice != null) bluetoothDevice.gatt.disconnect();
resetVariables();
addLog("Reconnect");
connectTrys = 0;
doConnect();
}
function startDFU() {
addLog("Старт программирования...");
updateBegin();
}
function addLog(logTXT) {
console.log(logTXT)
var time = new Date().toLocaleTimeString();
var logString = time + ": " + logTXT;
$("log").innerHTML += logString + "<br>";
}
function addClog(logTXT) {
console.log(logTXT);
}
function addAlog(logTXT) {
addLog(logTXT);
setStatus(logTXT);
}
function clearLog() {
$("log").innerHTML = "";
}
function setStatus(status) {
// addClog("Status: " + status);
$("percent").innerHTML = "Статус: " + status;
}
function updateFail(err) {
let s = "OTA error: " + err;
addAlog(s);
}
function decimalToHex(d, padding) {
var hex = Number(d).toString(16);
while (hex.length < 4) {
hex = "0" + hex;
}
return hex;
}
function hexToBytes(hex) {
for (var bytes = [], c = 0; c < hex.length; c += 2)
bytes.push(parseInt(hex.substr(c, 2), 16));
return new Uint8Array(bytes);
}
function bytesToHex(data) {
return new Uint8Array(data).reduce(function(memo, i) {
return memo + ("0" + i.toString(16)).slice(-2);
}, "");
}
function crc16_modbus(buffer) {
var crc = 0xFFFF;
var odd;
for (var i = 0; i < buffer.length; i++) {
crc = crc ^ buffer[i];
for (var j = 0; j < 8; j++) {
odd = crc & 0x0001;
crc = crc >> 1;
if (odd) {
crc = crc ^ 0xA001;
}
}
}
return crc;
};
function getHexCRC(data) {
var tempCRC = decimalToHex(crc16_modbus(hexToBytes(data)));
return tempCRC.substring(2, 4) + tempCRC.substring(0, 2);
}
function makeRandomID(length) {
var result = '';
var characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
var charactersLength = characters.length;
for (var i = 0; i < length; i++) {
result += characters.charAt(Math.floor(Math.random() * charactersLength));
}
return bytesToHex(new TextEncoder("utf-8").encode(result));
}
function hex(number, len) {
var str = (number.toString(16)).toUpperCase();
while (str.length < len) str = '0' + str;
return str;
}
function hexToBytes(hex) {
for (var bytes = [], c = 0; c < hex.length; c += 2)
bytes.push(parseInt(hex.substr(c, 2), 16));
return new Uint8Array(bytes);
}
function dump(ar, len) {
let s = '';
for(let i=0; i < len; i++) {
s += hex(ar[i],2);
}
return s;
}
function dump8(ar, len) {
let s = '';
for(let i=0; i < len; i++) {
s += hex(ar.getUint8(i),2);
}
return s;
}
function hex2ascii(hexx) {
var hex = hexx.toString();
var str = '';
for (var i = 0;
(i < hex.length && hex.substr(i, 2) !== '00'); i += 2)
str += String.fromCharCode(parseInt(hex.substr(i, 2), 16));
return str;
}
var crc32 = (function() {
let table = new Uint32Array(256);
for(var i=256; i--;) {
let tmp = i;
for(let k=8; k--;) {
tmp = tmp & 1 ? 0xEDB88320 ^ tmp >>> 1 : tmp >>> 1;
}
table[i] = tmp;
}
return function( data ) {
let crc = -1;
let l = data.length;
for(let i=0; i<l; i++) {
crc = crc >>> 8 ^ table[ crc & 255 ^ data[i] ];
}
return (crc >>> 0);
};
})();
function testOTAFirmware(data) {
let fsize = data.byteLength;
addClog("File size = 0x"+ fsize.toString(16));
if (fsize < 272)
return "Неправильный размер двоичной прошивки PHY6 OTA!";
if(fsize > 192*1024) // 208kB for BLE
return "Размер прошивки более 192 кбайт!";
let head = new DataView(data, 0, 272);
let h = {};
h.id = head.getUint32(0, true);
h.segs = head.getUint32(4, true);
h.start = head.getUint32(8, true);
h.size = head.getUint32(12, true);
addAlog("PHY6 OTA ID: "+hex(h.id, 4)+ ", Сегментов: " + h.segs + ", Старт: 0x"+hex(h.start, 8)+ ", Размер: " + h.size + " байт");
if(h.id != 0x36594850) // "PHY6"
return "Неверное id в заголовке PHY6 OTA!";
if(h.segs > 16)
return "Неверное количество сегментов в заголовке PHY6 OTA!";
if(h.size != fsize-4)
return "Неверный размер в заголовке PHY6 OTA!";
let fcrc = new Uint32Array(2);
fcrc[0] = crc32(new Uint8Array(data.slice(0, h.size)));
let x = new DataView(data, h.size, 4);
fcrc[1] = x.getUint32(0, true);
addClog("Файл CRC = 0x" + fcrc[1].toString(16) + ", Расчет CRC = 0x" + fcrc[0].toString(16));
if(fcrc[0] != fcrc[1]) {
return "Неправильный CRC в файле OTA!";
}
return "ok";
}
function getFirmwareArray(data, filename) {
addAlog("Файл: " + filename);
addClog("Файл: " + filename);
let s = testOTAFirmware(data);
if(s != "ok") {
addAlog(s);
blockCount = 0;
firmwareArray = null;
fwname = "";
//$("ldfrmw").innerHTML=s;
alert(s);
return;
}
firmwareArray = bytesToHex(data);
addAlog("Размер файла: " + (firmwareArray.length/2).toString(10) + " байт");
if (firmwareArray.length % 32 !== 0) { // pad last block to 16bytes
var padHex = "ffffffffffffffffffffffffffffffff";
firmwareArray += padHex.substr(0, 32 - firmwareArray.length % 32);
}
blockCount = firmwareArray.length / 32;
addAlog("Счетчик: " + blockCount + " блоков");
fwname = filename;
$('butStartDFU').disabled = false;
}
window.onload = function() {
document.querySelector("#file").addEventListener("change", function() {
let reader = new FileReader();
reader.fname = "";
reader.onload = function() {getFirmwareArray(this.result, this.fname);};
if (this.files[0] != null)
reader.readAsArrayBuffer(this.files[0]);
else
addLog("Файл не выбран"); }, false);
}
var ota_errors = [
'ok',
'Неверная команда',
'Не задан старт',
'Не заданы параметры',
'Неверные параметры',
'Неправильный размер пакета',
'Ошибка CRC16 пакета',
'Потеря пакетов',
'Ошибка записи в Flash',
'Ошибка в номере пакета',
'Ошибка идентификатора в файле программы',
'Ошибка CRC32 переданной программы'];
function get_msg_ota_err(err) {
if(err == 0)
return "ok";
if(err == 255)
return "OTA end";
if(err <= 11)
return ota_errors[err];
return "Неизвестная ошибка";
}
function OtaBlkParse(value) {
if(value.byteLength < 20) return;
var ota = {};
ota.err_flag = value.getUint8(0);
ota.version = value.getUint8(1);
ota.start_flag = value.getUint8(2);
ota.debug_flag = value.getUint8(3);
ota.program_offset = value.getUint32(4,true);
ota.pkt_index = value.getUint16(8,true);
ota.pkt_total = value.getUint16(10,true);
ota.fw_value = value.getUint32(12,true);
ota.crc32 = value.getUint32(16,true);
//addClog('otablk: '+dump8(value, value.byteLength));
addClog('OTA read: ver: '+hex(ota.version,2)+', err: '+ota.err_flag+' - '+get_msg_ota_err(ota.err_flag)+', dbg: '+ota.debug_flag+', start: '+ota.start_flag+', offs: 0x'+hex(ota.program_offset,8)+', idx: 0x'+hex(ota.pkt_index,4)+', total: 0x'+hex(ota.pkt_total,4)+', crc: 0x'+hex(ota.crc32,8));
}
function updateBegin() {
if (blockCount <= 0) {
addLog("Не выбран файл!");
return;
}
setTimeout(function() {
otaCharSend("00ff")
.then(_ => { otaCharacteristic.readValue().then(value => {
// otaCharSend("01ff"+firmwareArray.substring(16,24)+firmwareArray.substring(0,8)+hex((blockCount >> 8) | ((blockCount & 0xff) << 8),4))
otaCharSend("01ff")
.then(_ => { otaCharacteristic.readValue().then(value => {
if(value.byteLength >= 2 && value.getUint8(0) == 0) {
setTimeout(function() {
startTime = new Date().getTime();
sendOTAblock(0);
}, 100);
} else
addAlog("Ошибка N"+value.getUint8(0)+" OTA!");
}).catch(function(err) {updateFail(err); });
}).catch(function(err) {updateFail(err); });
}).catch(function(err) {updateFail(err); });
}).catch(function(err) {updateFail(err); });
}, 100);
}
function sendLastOTA() {
otaCharacteristic.readValue().then(value => {
if(value.byteLength >= 1 && value.getUint8(0) == 0xff)
addAlog("Программирование завершено за " + (new Date().getTime() - startTime) / 1000 + " секунды");
else
addAlog("Ошибка ("+value.getUint8(0)+") OTA: " + get_msg_ota_err(value.getUint8(0)));
}).catch(function(err) { updateFail(err); });
/* Сброс - отключен для теста
var data = "02ff";
otaCharSend(data).then(_ => {
addAlog("Программирование завершено за " + (new Date().getTime() - startTime) / 1000 + " секунды");
}).catch(function(err) {
updateFail(err);
}); */
}
function sendOTAblock(blockNr) {
if (blockNr >= blockCount) {
sendLastOTA();
return;
}
setStatus("Передан блок N: " + blockNr + " из " + blockCount + ", " + Math.floor(blockNr / (blockCount * 1.0) * 100) + "% успеха, время от старта " + (new Date().getTime() - startTime) / 1000.0 + " сек");
var blockNrString = getHexBLockCount(blockNr);
var blockString = blockNrString + firmwareArray.substring(blockNr * 32, blockNr * 32 + 32);
var blockCRC = getHexCRC(blockString);
otaCharSend(blockString + blockCRC).then(_ => {
if (blockNr >= blockCount - 1) {
sendLastOTA();
return;
}
setTimeout(function() {
if ((blockNr + 1) % 8 == 0) {
otaCharacteristic.readValue().then(value => {
if(value.byteLength >= 1 && value.getUint8(0) == 0)
sendOTAblock(blockNr + 1);
else {
let s = get_msg_ota_err(value.getUint8(0));
if(s != "ok")
addAlog("Ошибка ("+value.getUint8(0)+") на передаче блока "+blockNr+" OTA: "+s);
}
}).catch(function(err) { updateFail(err); });
} else
sendOTAblock(blockNr + 1);
}, 0);
}).catch(function(err) {
updateFail(err);
});
}
function getHexBLockCount(count) {
var tempHEX = decimalToHex(count);
return tempHEX.substring(2, 4) + tempHEX.substring(0, 2);
}
var otaCharSend = function(data) {
return new Promise(function(resolve, reject) {
//addClog("OTA send: " + data);
otaCharacteristic.writeValue(hexToBytes(data)).then(function(character) {
resolve("ok");
}).catch(function(err) {
reject("Ошибка при отправке данных");
});
});
}
var mainCharSend = function(data, characteristic) {
return new Promise(function(resolve, reject) {
addClog("Send: " + data);
characteristic.writeValue(hexToBytes(data)).then(function(character) {
resolve("ok");
}).catch(function(err) {
reject("Ошибка при отправке данных");
});
});
}
function ReadAddr(addr) {
if(myCharacteristic) {
let blk = new Uint8Array([0xdb, addr&0xff, (addr>>8)&0xff, (addr>>16)&0xff, (addr>>24)&0xff]);
myCharacteristic.writeValue(blk).then(_ => {
startTime = new Date().getTime();
addAlog("Чтение 16 байт из 0x"+hex(addr,8)+"...");
});
}
}
function WriteAddr(addr, data) {
if(myCharacteristic) {
len = data.length;
if(len != 0 && len <= 16) {
let blk = new Uint8Array(len + 5);
blk.set([0xdb, addr&0xff, (addr>>8)&0xff, (addr>>16)&0xff, (addr>>24)&0xff]);
blk.set(data, 5);
console.log(blk);
addAlog("Запись "+len+" байт в 0x"+hex(addr,6)+"...");
myCharacteristic.writeValue(blk);
} else {
console.log(data);
addClog('Должно быть от 1 до 16 байт!');
}
}
}
function InfoReadAddr() {
if(myCharacteristic) {
let faddr = parseInt($('inputAddr').value, 16);
ReadAddr(faddr);
}
}
function WriteCmd(data) {
if(myCharacteristic) {
len = data.length;
if(len != 0 && len <= 20) {
let blk = new Uint8Array(data);
console.log(blk);
myCharacteristic.writeValue(blk);
} else {
console.log(data);
addClog('Должно быть от 1 до 20 байт!');
}
}
}
function WriteData() {
let addr = parseInt($('inputAddr').value, 16);
let data = hexToBytes($('inputData').value);
if(data.length != 0 && data.length <= 16)
WriteAddr(addr, data);
else
addClog('Должно быть от 1 до 16 hex байт!');
}
function CmdData() {
let data = hexToBytes($('inputCmdData').value);
if(data.length != 0 && data.length <= 20)
WriteCmd(data);
else
addClog('Должно быть от 1 до 20 hex байт!');
}
function CustomBlkParse(value) {
let len = value.byteLength;
if(len == 0) return;
len--; // size from cmd
let blkid = value.getUint8(0);
s = 'Ответ на команду id: '+hex(blkid,2)+' data: '+bytesToHex(value.buffer.slice(1));
addLog(s);
if(blkid == 0xdb && value.byteLength > 4) {
len -= 4;
let addr = value.getUint32(1,true);
let s = bytesToHex(value.buffer.slice(5), len);
$('inputData').value = s;
addLog(hex(addr,8)+':'+s);
setStatus("Считано "+len+" байт из 0x" + hex(addr,8));
} else
addClog('blk: '+dump8(value, value.byteLength));
}
var url;
function download(data, filename, type) {
var file = new Blob([data], {type: type});
if (window.navigator.msSaveOrOpenBlob) { // ie10+
window.navigator.msSaveOrOpenBlob(file, filename);
} else { // ff, chrome
url = URL.createObjectURL(file);
let a = document.createElement("a");
a.href = url;
a.download = filename;
document.body.appendChild(a);
a.click();
setTimeout(function(){document.body.removeChild(a);window.URL.revokeObjectURL(url);},0);
URL.revokeObjectURL(url);
}
}
</script>
<big><big>PHY62x2-BTHome</big></big> <a href="https://github.com/pvvx/THB2">&#9432;</a><hr>
<button type="button" onclick="connect();">Соединение</button>
<button type="button" onclick="reConnect();">Переподключение</button><br><br>
<label for="namePrefix">Префикс названия устройств(а)</label>
<input type="text" id="namePrefix" value="" placeholder="THB, BT"><br><hr>
Выбор файла прошивки: <input type="file" accept=".bin" id="file"/><br>
<div id="percent">Состояние: Ожидание соединения с устройством</div>
<button type="button"id="butStartDFU" disabled="true" onclick="startDFU();">Старт программирования</button>
<br><hr>
Чтение и запись памяти:<br>
Адрес (hex): <input size="8" type="text" id="inputAddr" value="11000000" maxlength="8">
<input type="button" id="butReadAddr" onclick="InfoReadAddr()" disabled="true" value="Читать">
Данные (hex): <input size="40" type="text" id="inputData" value="?" maxlength="32">
<input type="button" id="butWriteData" onclick="WriteData()" disabled="true" value="Записать"><hr>
<input type="button" id="butCmdData" onclick="CmdData()" disabled="true" value="Команда">
<input size="40" type="text" id="inputCmdData" value="55" maxlength="40"><hr>
<button type="button" onclick="clearLog();">Очистить лог</button><br>
<div id="log"></div>
</body></html>

BIN
bthome_phy6222/web/test.bin Normal file

Binary file not shown.