Merge remote-tracking branch 'upstream/dev'
This commit is contained in:
commit
ee53fb83e0
359
Bluetooth.h
359
Bluetooth.h
@ -1,4 +1,4 @@
|
||||
// Copyright (C) 2023, Mark Qvist
|
||||
// Copyright (C) 2024, Mark Qvist
|
||||
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
@ -22,8 +22,8 @@
|
||||
#elif HAS_BLE == true
|
||||
#include "esp_bt_main.h"
|
||||
#include "esp_bt_device.h"
|
||||
// TODO: Remove
|
||||
#define SerialBT Serial
|
||||
#include "src/ble/BLESerial.h"
|
||||
BLESerial SerialBT;
|
||||
#endif
|
||||
|
||||
#elif MCU_VARIANT == MCU_NRF52
|
||||
@ -36,6 +36,7 @@
|
||||
#endif
|
||||
|
||||
#define BT_PAIRING_TIMEOUT 35000
|
||||
#define BLE_FLUSH_TIMEOUT 20
|
||||
uint32_t bt_pairing_started = 0;
|
||||
|
||||
#define BT_DEV_ADDR_LEN 6
|
||||
@ -59,6 +60,7 @@ char bt_devname[11];
|
||||
}
|
||||
|
||||
void bt_stop() {
|
||||
//display_unblank();
|
||||
if (bt_state != BT_STATE_OFF) {
|
||||
SerialBT.end();
|
||||
bt_allow_pairing = false;
|
||||
@ -67,6 +69,7 @@ char bt_devname[11];
|
||||
}
|
||||
|
||||
void bt_start() {
|
||||
//display_unblank();
|
||||
if (bt_state == BT_STATE_OFF) {
|
||||
SerialBT.begin(bt_devname);
|
||||
bt_state = BT_STATE_ON;
|
||||
@ -74,6 +77,7 @@ char bt_devname[11];
|
||||
}
|
||||
|
||||
void bt_enable_pairing() {
|
||||
//display_unblank();
|
||||
if (bt_state == BT_STATE_OFF) bt_start();
|
||||
bt_allow_pairing = true;
|
||||
bt_pairing_started = millis();
|
||||
@ -81,12 +85,14 @@ char bt_devname[11];
|
||||
}
|
||||
|
||||
void bt_disable_pairing() {
|
||||
//display_unblank();
|
||||
bt_allow_pairing = false;
|
||||
bt_ssp_pin = 0;
|
||||
bt_state = BT_STATE_ON;
|
||||
}
|
||||
|
||||
void bt_pairing_complete(boolean success) {
|
||||
//display_unblank();
|
||||
if (success) {
|
||||
bt_disable_pairing();
|
||||
} else {
|
||||
@ -94,7 +100,8 @@ char bt_devname[11];
|
||||
}
|
||||
}
|
||||
|
||||
void bt_connection_callback(esp_spp_cb_event_t event, esp_spp_cb_param_t *param){
|
||||
void bt_connection_callback(esp_spp_cb_event_t event, esp_spp_cb_param_t *param) {
|
||||
//display_unblank();
|
||||
if(event == ESP_SPP_SRV_OPEN_EVT) {
|
||||
bt_state = BT_STATE_CONNECTED;
|
||||
cable_state = CABLE_STATE_DISCONNECTED;
|
||||
@ -157,25 +164,122 @@ char bt_devname[11];
|
||||
}
|
||||
|
||||
#elif HAS_BLE == true
|
||||
void bt_stop() {
|
||||
if (bt_state != BT_STATE_OFF) {
|
||||
bt_allow_pairing = false;
|
||||
bt_state = BT_STATE_OFF;
|
||||
}
|
||||
}
|
||||
BLESecurity *ble_security = new BLESecurity();
|
||||
bool ble_authenticated = false;
|
||||
uint32_t pairing_pin = 0;
|
||||
|
||||
void bt_flush() { if (bt_state == BT_STATE_CONNECTED) { SerialBT.flush(); } }
|
||||
|
||||
void bt_disable_pairing() {
|
||||
//display_unblank();
|
||||
bt_allow_pairing = false;
|
||||
bt_ssp_pin = 0;
|
||||
bt_state = BT_STATE_ON;
|
||||
}
|
||||
|
||||
void bt_connect_callback(uint16_t conn_handle) {
|
||||
void bt_passkey_notify_callback(uint32_t passkey) {
|
||||
// Serial.printf("Got passkey notification: %d\n", passkey);
|
||||
bt_ssp_pin = passkey;
|
||||
bt_state = BT_STATE_PAIRING;
|
||||
bt_allow_pairing = true;
|
||||
bt_pairing_started = millis();
|
||||
kiss_indicate_btpin();
|
||||
}
|
||||
|
||||
bool bt_confirm_pin_callback(uint32_t pin) {
|
||||
// Serial.printf("Confirm PIN callback: %d\n", pin);
|
||||
return true;
|
||||
}
|
||||
|
||||
void bt_debond_all() {
|
||||
// Serial.println("Debonding all");
|
||||
int dev_num = esp_ble_get_bond_device_num();
|
||||
esp_ble_bond_dev_t *dev_list = (esp_ble_bond_dev_t *)malloc(sizeof(esp_ble_bond_dev_t) * dev_num);
|
||||
esp_ble_get_bond_device_list(&dev_num, dev_list);
|
||||
for (int i = 0; i < dev_num; i++) { esp_ble_remove_bond_device(dev_list[i].bd_addr); }
|
||||
free(dev_list);
|
||||
}
|
||||
|
||||
void bt_update_passkey() {
|
||||
// Serial.println("Updating passkey");
|
||||
pairing_pin = random(899999)+100000;
|
||||
bt_ssp_pin = pairing_pin;
|
||||
}
|
||||
|
||||
uint32_t bt_passkey_callback() {
|
||||
// Serial.println("API passkey request");
|
||||
if (pairing_pin == 0) { bt_update_passkey(); }
|
||||
return pairing_pin;
|
||||
}
|
||||
|
||||
bool bt_client_authenticated() {
|
||||
return ble_authenticated;
|
||||
}
|
||||
|
||||
void bt_security_setup() {
|
||||
uint32_t passkey = bt_passkey_callback();
|
||||
|
||||
// Serial.printf("Executing BT security setup, passkey is %d\n", passkey);
|
||||
|
||||
uint8_t key_size = 16;
|
||||
uint8_t init_key = ESP_BLE_ENC_KEY_MASK | ESP_BLE_ID_KEY_MASK;
|
||||
uint8_t rsp_key = ESP_BLE_ENC_KEY_MASK | ESP_BLE_ID_KEY_MASK;
|
||||
|
||||
esp_ble_auth_req_t auth_req = ESP_LE_AUTH_REQ_SC_MITM_BOND;
|
||||
uint8_t auth_option = ESP_BLE_ONLY_ACCEPT_SPECIFIED_AUTH_ENABLE;
|
||||
uint8_t oob_support = ESP_BLE_OOB_DISABLE;
|
||||
|
||||
esp_ble_io_cap_t iocap = ESP_IO_CAP_OUT;
|
||||
|
||||
esp_ble_gap_set_security_param(ESP_BLE_SM_SET_STATIC_PASSKEY, &passkey, sizeof(uint32_t));
|
||||
esp_ble_gap_set_security_param(ESP_BLE_SM_AUTHEN_REQ_MODE, &auth_req, sizeof(uint8_t));
|
||||
esp_ble_gap_set_security_param(ESP_BLE_SM_IOCAP_MODE, &iocap, sizeof(uint8_t));
|
||||
esp_ble_gap_set_security_param(ESP_BLE_SM_MAX_KEY_SIZE, &key_size, sizeof(uint8_t));
|
||||
esp_ble_gap_set_security_param(ESP_BLE_SM_ONLY_ACCEPT_SPECIFIED_SEC_AUTH, &auth_option, sizeof(uint8_t));
|
||||
esp_ble_gap_set_security_param(ESP_BLE_SM_OOB_SUPPORT, &oob_support, sizeof(uint8_t));
|
||||
esp_ble_gap_set_security_param(ESP_BLE_SM_SET_INIT_KEY, &init_key, sizeof(uint8_t));
|
||||
esp_ble_gap_set_security_param(ESP_BLE_SM_SET_RSP_KEY, &rsp_key, sizeof(uint8_t));
|
||||
}
|
||||
|
||||
bool bt_security_request_callback() {
|
||||
if (bt_allow_pairing) {
|
||||
// Serial.println("Accepting security request");
|
||||
return true;
|
||||
} else {
|
||||
// Serial.println("Rejecting security request");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
void bt_authentication_complete_callback(esp_ble_auth_cmpl_t auth_result) {
|
||||
if (auth_result.success == true) {
|
||||
// Serial.println("Authentication success");
|
||||
ble_authenticated = true;
|
||||
bt_state = BT_STATE_CONNECTED;
|
||||
} else {
|
||||
// Serial.println("Authentication fail");
|
||||
ble_authenticated = false;
|
||||
bt_state = BT_STATE_ON;
|
||||
bt_security_setup();
|
||||
}
|
||||
bt_allow_pairing = false;
|
||||
bt_ssp_pin = 0;
|
||||
}
|
||||
|
||||
void bt_connect_callback(BLEServer *server) {
|
||||
// uint16_t conn_id = server->getConnId();
|
||||
// Serial.printf("Connected: %d\n", conn_id);
|
||||
//display_unblank();
|
||||
ble_authenticated = false;
|
||||
bt_state = BT_STATE_CONNECTED;
|
||||
cable_state = CABLE_STATE_DISCONNECTED;
|
||||
}
|
||||
|
||||
void bt_disconnect_callback(uint16_t conn_handle, uint8_t reason) {
|
||||
void bt_disconnect_callback(BLEServer *server) {
|
||||
// uint16_t conn_id = server->getConnId();
|
||||
// Serial.printf("Disconnected: %d\n", conn_id);
|
||||
//display_unblank();
|
||||
ble_authenticated = false;
|
||||
bt_state = BT_STATE_ON;
|
||||
}
|
||||
|
||||
@ -200,8 +304,8 @@ char bt_devname[11];
|
||||
sprintf(bt_devname, "RNode %02X%02X", bt_dh[14], bt_dh[15]);
|
||||
free(data);
|
||||
|
||||
// TODO: Implement GAP & GATT for RNode comms over BLE
|
||||
|
||||
bt_security_setup();
|
||||
|
||||
bt_ready = true;
|
||||
return true;
|
||||
|
||||
@ -212,9 +316,20 @@ char bt_devname[11];
|
||||
}
|
||||
|
||||
void bt_start() {
|
||||
//display_unblank();
|
||||
if (bt_state == BT_STATE_OFF) {
|
||||
bt_state = BT_STATE_ON;
|
||||
// TODO: Implement
|
||||
SerialBT.begin(bt_devname);
|
||||
SerialBT.setTimeout(10);
|
||||
}
|
||||
}
|
||||
|
||||
void bt_stop() {
|
||||
//display_unblank();
|
||||
if (bt_state != BT_STATE_OFF) {
|
||||
bt_allow_pairing = false;
|
||||
bt_state = BT_STATE_OFF;
|
||||
SerialBT.end();
|
||||
}
|
||||
}
|
||||
|
||||
@ -229,7 +344,13 @@ char bt_devname[11];
|
||||
}
|
||||
|
||||
void bt_enable_pairing() {
|
||||
//display_unblank();
|
||||
if (bt_state == BT_STATE_OFF) bt_start();
|
||||
|
||||
bt_security_setup();
|
||||
//bt_debond_all();
|
||||
//bt_update_passkey();
|
||||
|
||||
bt_allow_pairing = true;
|
||||
bt_pairing_started = millis();
|
||||
bt_state = BT_STATE_PAIRING;
|
||||
@ -239,26 +360,31 @@ char bt_devname[11];
|
||||
if (bt_allow_pairing && millis()-bt_pairing_started >= BT_PAIRING_TIMEOUT) {
|
||||
bt_disable_pairing();
|
||||
}
|
||||
if (bt_state == BT_STATE_CONNECTED && millis()-SerialBT.lastFlushTime >= BLE_FLUSH_TIMEOUT) {
|
||||
if (SerialBT.transmitBufferLength > 0) {
|
||||
bt_flush();
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#elif MCU_VARIANT == MCU_NRF52
|
||||
uint8_t eeprom_read(uint32_t mapped_addr);
|
||||
uint8_t eeprom_read(uint32_t mapped_addr);
|
||||
|
||||
void bt_stop() {
|
||||
if (bt_state != BT_STATE_OFF) {
|
||||
bt_allow_pairing = false;
|
||||
bt_state = BT_STATE_OFF;
|
||||
void bt_stop() {
|
||||
if (bt_state != BT_STATE_OFF) {
|
||||
bt_allow_pairing = false;
|
||||
bt_state = BT_STATE_OFF;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void bt_disable_pairing() {
|
||||
bt_allow_pairing = false;
|
||||
bt_ssp_pin = 0;
|
||||
bt_state = BT_STATE_ON;
|
||||
}
|
||||
void bt_disable_pairing() {
|
||||
bt_allow_pairing = false;
|
||||
bt_ssp_pin = 0;
|
||||
bt_state = BT_STATE_ON;
|
||||
}
|
||||
|
||||
void bt_pairing_complete(uint16_t conn_handle, uint8_t auth_status) {
|
||||
void bt_pairing_complete(uint16_t conn_handle, uint8_t auth_status) {
|
||||
if (auth_status == BLE_GAP_SEC_STATUS_SUCCESS) {
|
||||
BLEConnection* connection = Bluefruit.Connection(conn_handle);
|
||||
|
||||
@ -291,24 +417,23 @@ void bt_pairing_complete(uint16_t conn_handle, uint8_t auth_status) {
|
||||
} else {
|
||||
bt_ssp_pin = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool bt_passkey_callback(uint16_t conn_handle, uint8_t const passkey[6], bool match_request) {
|
||||
bool bt_passkey_callback(uint16_t conn_handle, uint8_t const passkey[6], bool match_request) {
|
||||
for (int i = 0; i < 6; i++) {
|
||||
// multiply by tens however many times needed to make numbers appear in order
|
||||
bt_ssp_pin += ((int)passkey[i] - 48) * pow(10, 5-i);
|
||||
// multiply by tens however many times needed to make numbers appear in order
|
||||
bt_ssp_pin += ((int)passkey[i] - 48) * pow(10, 5-i);
|
||||
}
|
||||
kiss_indicate_btpin();
|
||||
if (bt_allow_pairing) {
|
||||
return true;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
void bt_connect_callback(uint16_t conn_handle) {
|
||||
void bt_connect_callback(uint16_t conn_handle) {
|
||||
bt_state = BT_STATE_CONNECTED;
|
||||
cable_state = CABLE_STATE_DISCONNECTED;
|
||||
|
||||
BLEConnection* conn = Bluefruit.Connection(conn_handle);
|
||||
conn->requestPHY(BLE_GAP_PHY_2MBPS);
|
||||
conn->requestMtuExchange(512+3);
|
||||
@ -321,93 +446,91 @@ void bt_disconnect_callback(uint16_t conn_handle, uint8_t reason) {
|
||||
}
|
||||
}
|
||||
|
||||
bool bt_setup_hw() {
|
||||
if (!bt_ready) {
|
||||
#if HAS_EEPROM
|
||||
if (EEPROM.read(eeprom_addr(ADDR_CONF_BT)) == BT_ENABLE_BYTE) {
|
||||
#else
|
||||
if (eeprom_read(eeprom_addr(ADDR_CONF_BT)) == BT_ENABLE_BYTE) {
|
||||
#endif
|
||||
bt_enabled = true;
|
||||
} else {
|
||||
bt_enabled = false;
|
||||
}
|
||||
Bluefruit.configPrphBandwidth(BANDWIDTH_MAX);
|
||||
Bluefruit.autoConnLed(false);
|
||||
if (Bluefruit.begin()) {
|
||||
Bluefruit.setTxPower(8); // Check bluefruit.h for supported values
|
||||
Bluefruit.Security.setIOCaps(true, false, false); // display, yes; yes / no, no; keyboard, no
|
||||
// This device is indeed capable of yes / no through the pairing mode
|
||||
// being set, but I have chosen to set it thus to force the input of the
|
||||
// pin on the device initiating the pairing. This prevents it from being
|
||||
// paired with automatically by a hypothetical malicious device nearby
|
||||
// without physical access to the RNode.
|
||||
|
||||
Bluefruit.Security.setMITM(true);
|
||||
Bluefruit.Security.setPairPasskeyCallback(bt_passkey_callback);
|
||||
Bluefruit.Security.setSecuredCallback(bt_connect_callback);
|
||||
Bluefruit.Periph.setDisconnectCallback(bt_disconnect_callback);
|
||||
Bluefruit.Security.setPairCompleteCallback(bt_pairing_complete);
|
||||
Bluefruit.Periph.setConnInterval(6, 12); // 7.5 - 15 ms
|
||||
|
||||
const ble_gap_addr_t gap_addr = Bluefruit.getAddr();
|
||||
char *data = (char*)malloc(BT_DEV_ADDR_LEN+1);
|
||||
for (int i = 0; i < BT_DEV_ADDR_LEN; i++) {
|
||||
data[i] = gap_addr.addr[i];
|
||||
}
|
||||
bool bt_setup_hw() {
|
||||
if (!bt_ready) {
|
||||
#if HAS_EEPROM
|
||||
data[BT_DEV_ADDR_LEN] = EEPROM.read(eeprom_addr(ADDR_SIGNATURE));
|
||||
if (EEPROM.read(eeprom_addr(ADDR_CONF_BT)) == BT_ENABLE_BYTE) {
|
||||
#else
|
||||
data[BT_DEV_ADDR_LEN] = eeprom_read(eeprom_addr(ADDR_SIGNATURE));
|
||||
if (eeprom_read(eeprom_addr(ADDR_CONF_BT)) == BT_ENABLE_BYTE) {
|
||||
#endif
|
||||
unsigned char *hash = MD5::make_hash(data, BT_DEV_ADDR_LEN);
|
||||
memcpy(bt_dh, hash, BT_DEV_HASH_LEN);
|
||||
sprintf(bt_devname, "openCom XL %02X%02X", bt_dh[14], bt_dh[15]);
|
||||
free(data);
|
||||
bt_enabled = true;
|
||||
} else {
|
||||
bt_enabled = false;
|
||||
}
|
||||
Bluefruit.configPrphBandwidth(BANDWIDTH_MAX);
|
||||
Bluefruit.autoConnLed(false);
|
||||
if (Bluefruit.begin()) {
|
||||
Bluefruit.setTxPower(8); // Check bluefruit.h for supported values
|
||||
Bluefruit.Security.setIOCaps(true, false, false); // display, yes; yes / no, no; keyboard, no
|
||||
// This device is indeed capable of yes / no through the pairing mode
|
||||
// being set, but I have chosen to set it thus to force the input of the
|
||||
// pin on the device initiating the pairing.
|
||||
|
||||
bt_ready = true;
|
||||
return true;
|
||||
Bluefruit.Security.setMITM(true);
|
||||
Bluefruit.Security.setPairPasskeyCallback(bt_passkey_callback);
|
||||
Bluefruit.Security.setSecuredCallback(bt_connect_callback);
|
||||
Bluefruit.Periph.setDisconnectCallback(bt_disconnect_callback);
|
||||
Bluefruit.Security.setPairCompleteCallback(bt_pairing_complete);
|
||||
Bluefruit.Periph.setConnInterval(6, 12); // 7.5 - 15 ms
|
||||
|
||||
const ble_gap_addr_t gap_addr = Bluefruit.getAddr();
|
||||
char *data = (char*)malloc(BT_DEV_ADDR_LEN+1);
|
||||
for (int i = 0; i < BT_DEV_ADDR_LEN; i++) {
|
||||
data[i] = gap_addr.addr[i];
|
||||
}
|
||||
#if HAS_EEPROM
|
||||
data[BT_DEV_ADDR_LEN] = EEPROM.read(eeprom_addr(ADDR_SIGNATURE));
|
||||
#else
|
||||
data[BT_DEV_ADDR_LEN] = eeprom_read(eeprom_addr(ADDR_SIGNATURE));
|
||||
#endif
|
||||
unsigned char *hash = MD5::make_hash(data, BT_DEV_ADDR_LEN);
|
||||
memcpy(bt_dh, hash, BT_DEV_HASH_LEN);
|
||||
sprintf(bt_devname, "openCom XL %02X%02X", bt_dh[14], bt_dh[15]);
|
||||
free(data);
|
||||
|
||||
bt_ready = true;
|
||||
return true;
|
||||
|
||||
} else { return false; }
|
||||
} else { return false; }
|
||||
} else { return false; }
|
||||
}
|
||||
}
|
||||
|
||||
void bt_start() {
|
||||
if (bt_state == BT_STATE_OFF) {
|
||||
Bluefruit.setName(bt_devname);
|
||||
bledis.setManufacturer(BLE_MANUFACTURER);
|
||||
bledis.setModel(BLE_MODEL);
|
||||
// start device information service
|
||||
bledis.begin();
|
||||
void bt_start() {
|
||||
if (bt_state == BT_STATE_OFF) {
|
||||
Bluefruit.setName(bt_devname);
|
||||
bledis.setManufacturer(BLE_MANUFACTURER);
|
||||
bledis.setModel(BLE_MODEL);
|
||||
// start device information service
|
||||
bledis.begin();
|
||||
|
||||
if (!SerialBT_init) {
|
||||
if (!SerialBT_init) {
|
||||
|
||||
SerialBT.bufferTXD(true); // enable buffering
|
||||
SerialBT.bufferTXD(true); // enable buffering
|
||||
|
||||
SerialBT.setPermission(SECMODE_ENC_WITH_MITM, SECMODE_ENC_WITH_MITM); // enable encryption for BLE serial
|
||||
SerialBT.begin();
|
||||
SerialBT_init = true;
|
||||
}
|
||||
SerialBT.setPermission(SECMODE_ENC_WITH_MITM, SECMODE_ENC_WITH_MITM); // enable encryption for BLE serial
|
||||
SerialBT.begin();
|
||||
SerialBT_init = true;
|
||||
}
|
||||
|
||||
blebas.begin();
|
||||
blebas.begin();
|
||||
|
||||
Bluefruit.Advertising.addFlags(BLE_GAP_ADV_FLAGS_LE_ONLY_GENERAL_DISC_MODE);
|
||||
Bluefruit.Advertising.addTxPower();
|
||||
Bluefruit.Advertising.addFlags(BLE_GAP_ADV_FLAGS_LE_ONLY_GENERAL_DISC_MODE);
|
||||
Bluefruit.Advertising.addTxPower();
|
||||
|
||||
// Include bleuart 128-bit uuid
|
||||
Bluefruit.Advertising.addService(SerialBT);
|
||||
// Include bleuart 128-bit uuid
|
||||
Bluefruit.Advertising.addService(SerialBT);
|
||||
|
||||
// There is no room for Name in Advertising packet
|
||||
// Use Scan response for Name
|
||||
Bluefruit.ScanResponse.addName();
|
||||
// There is no room for Name in Advertising packet
|
||||
// Use Scan response for Name
|
||||
Bluefruit.ScanResponse.addName();
|
||||
|
||||
Bluefruit.Advertising.start(0);
|
||||
Bluefruit.Advertising.start(0);
|
||||
|
||||
bt_state = BT_STATE_ON;
|
||||
}
|
||||
}
|
||||
bt_state = BT_STATE_ON;
|
||||
}
|
||||
}
|
||||
|
||||
bool bt_init() {
|
||||
bool bt_init() {
|
||||
bt_state = BT_STATE_OFF;
|
||||
if (bt_setup_hw()) {
|
||||
if (bt_enabled && !console_active) bt_start();
|
||||
@ -415,18 +538,18 @@ bool bt_init() {
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
void bt_enable_pairing() {
|
||||
if (bt_state == BT_STATE_OFF) bt_start();
|
||||
bt_allow_pairing = true;
|
||||
bt_pairing_started = millis();
|
||||
bt_state = BT_STATE_PAIRING;
|
||||
}
|
||||
|
||||
void update_bt() {
|
||||
if (bt_allow_pairing && millis()-bt_pairing_started >= BT_PAIRING_TIMEOUT) {
|
||||
bt_disable_pairing();
|
||||
}
|
||||
}
|
||||
|
||||
void bt_enable_pairing() {
|
||||
if (bt_state == BT_STATE_OFF) bt_start();
|
||||
bt_allow_pairing = true;
|
||||
bt_pairing_started = millis();
|
||||
bt_state = BT_STATE_PAIRING;
|
||||
}
|
||||
|
||||
void update_bt() {
|
||||
if (bt_allow_pairing && millis()-bt_pairing_started >= BT_PAIRING_TIMEOUT) {
|
||||
bt_disable_pairing();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
369
Boards.h
369
Boards.h
@ -25,23 +25,102 @@
|
||||
#define MCU_ESP32 0x81
|
||||
#define MCU_NRF52 0x71
|
||||
|
||||
// Boards
|
||||
#define BOARD_RNODE 0x31
|
||||
#define BOARD_HMBRW 0x32
|
||||
// Products, boards and models. Grouped by manufacturer.
|
||||
// Below are the original RNodes, sold by Mark Qvist.
|
||||
#define PRODUCT_RNODE 0x03 // RNode devices
|
||||
#define BOARD_RNODE 0x31 // Original v1.0 RNode
|
||||
#define MODEL_A4 0xA4 // RNode v1.0, 433 MHz
|
||||
#define MODEL_A9 0xA9 // RNode v1.0, 868 MHz
|
||||
|
||||
#define BOARD_RNODE_NG_20 0x40 // RNode hardware revision v2.0
|
||||
#define MODEL_A3 0xA3 // RNode v2.0, 433 MHz
|
||||
#define MODEL_A8 0xA8 // RNode v2.0, 868 MHz
|
||||
|
||||
#define BOARD_RNODE_NG_21 0x41 // RNode hardware revision v2.1
|
||||
#define MODEL_A2 0xA2 // RNode v2.1, 433 MHz
|
||||
#define MODEL_A7 0xA7 // RNode v2.1, 868 MHz
|
||||
|
||||
#define BOARD_RNODE_NG_22 0x42 // RNode hardware revision v2.2 (T3S3)
|
||||
#define MODEL_A1 0xA1 // RNode v2.2, 433 MHz with SX1268
|
||||
#define MODEL_A5 0xA5 // RNode v2.2, 433 MHz with SX1278
|
||||
#define MODEL_A6 0xA6 // RNode v2.2, 868 MHz with SX1262
|
||||
#define MODEL_AA 0xAA // RNode v2.2, 868 MHz with SX1276
|
||||
|
||||
#define PRODUCT_TBEAM 0xE0 // T-Beam - sold by LilyGO
|
||||
#define BOARD_TBEAM 0x33
|
||||
#define MODEL_E4 0xE4 // T-Beam SX1278, 433 Mhz
|
||||
#define MODEL_E9 0xE9 // T-Beam SX1276, 868 Mhz
|
||||
#define MODEL_E3 0xE3 // T-Beam SX1268, 433 Mhz
|
||||
#define MODEL_E8 0xE8 // T-Beam SX1262, 868 Mhz
|
||||
|
||||
#define PRODUCT_TDECK_V1 0xD0 // T-Deck - sold by LilyGO
|
||||
#define BOARD_TDECK 0x3B
|
||||
#define MODEL_D4 0xD4 // LilyGO T-Deck, 433 MHz
|
||||
#define MODEL_D9 0xD9 // LilyGO T-Deck, 868 MHz
|
||||
|
||||
#define PRODUCT_TBEAM_S_V1 0xEA // T-Beam Supreme - sold by LilyGO
|
||||
#define BOARD_TBEAM_S_V1 0x3D
|
||||
#define MODEL_DB 0xDB // LilyGO T-Beam Supreme, 433 MHz
|
||||
#define MODEL_DC 0xDC // LilyGO T-Beam Supreme, 868 MHz
|
||||
|
||||
#define PRODUCT_T32_10 0xB2 // T3 v1.0 - sold by LilyGO
|
||||
#define BOARD_LORA32_V1_0 0x39
|
||||
#define MODEL_BA 0xBA // LilyGO T3 v1.0, 433 MHz
|
||||
#define MODEL_BB 0xBB // LilyGO T3 v1.0, 868 MHz
|
||||
|
||||
#define PRODUCT_T32_20 0xB0 // T3 v2.0 - sold by LilyGO
|
||||
#define BOARD_LORA32_V2_0 0x36
|
||||
#define MODEL_B3 0xB3 // LilyGO T3 v2.0, 433 MHz
|
||||
#define MODEL_B8 0xB8 // LilyGO T3 v2.0, 868 MHz
|
||||
|
||||
#define PRODUCT_T32_21 0xB1 // T3 v2.1 - sold by LilyGO
|
||||
#define BOARD_LORA32_V2_1 0x37
|
||||
#define MODEL_B4 0xB4 // LilyGO T3 v2.1, 433 MHz
|
||||
#define MODEL_B9 0xB9 // LilyGO T3 v2.1, 868 MHz
|
||||
|
||||
#define BOARD_T3S3 0x42 // T3S3 - sold by LilyGO
|
||||
#define MODEL_A1 0xA1 // T3S3 SX1262 868/915 MHz
|
||||
#define MODEL_AB 0xAB // T3S3 SX1276 868/915 MHz
|
||||
#define MODEL_A5 0xA5 // T3S3 SX1278 433 MHz
|
||||
#define MODEL_AB 0xAB // T3S3 SX1280 2.4 GHz w/ PA
|
||||
|
||||
#define PRODUCT_TECHO 0x15 // LilyGO T-Echo devices
|
||||
#define BOARD_TECHO 0x43
|
||||
#define MODEL_16 0x16 // T-Echo 433 MHz
|
||||
#define MODEL_17 0x17 // T-Echo 868/915 MHz
|
||||
|
||||
|
||||
#define PRODUCT_H32_V2 0xC0 // LoRa32 v2 - sold by Heltec
|
||||
#define BOARD_HELTEC32_V2 0x38
|
||||
#define MODEL_C4 0xC4 // Heltec Lora32 v2, 433 MHz
|
||||
#define MODEL_C9 0xC9 // Heltec Lora32 v2, 868 MHz
|
||||
|
||||
#define PRODUCT_H32_V3 0xC1 // LoRa32 v3 - sold by Heltec
|
||||
#define BOARD_HELTEC32_V3 0x3A
|
||||
#define MODEL_C5 0xC5 // Heltec Lora32 v3, 433 MHz
|
||||
#define MODEL_CA 0xCA // Heltec Lora32 v3, 868 MHz
|
||||
|
||||
#define PRODUCT_RAK4631 0x10 // RAK4631 - sold by RAKWireless
|
||||
#define BOARD_RAK4631 0x51
|
||||
#define MODEL_11 0x11 // RAK4631, 433 MHz
|
||||
#define MODEL_12 0x12 // RAK4631, 868 MHz
|
||||
#define MODEL_13 0x13 // RAK4631, 433MHz with WisBlock SX1280 module (LIBSYS002)
|
||||
#define MODEL_14 0x14 // RAK4631, 868/915 MHz with WisBlock SX1280 module (LIBSYS002)
|
||||
|
||||
#define PRODUCT_OPENCOM_XL 0x20 // openCom XL - sold by Liberated Embedded Systems
|
||||
#define BOARD_OPENCOM_XL 0x52
|
||||
#define MODEL_21 0x21 // openCom XL, 868/915 MHz
|
||||
|
||||
#define BOARD_E22_ESP32 0x44 // Custom Ebyte E22 board design for meshtastic, source:
|
||||
// https://github.com/NanoVHF/Meshtastic-DIY/blob/main/Schematics/E-Byte_E22/Mesh_Ebyte_E22-XXXM30S.pdf
|
||||
|
||||
#define PRODUCT_HMBRW 0xF0
|
||||
#define BOARD_HMBRW 0x32
|
||||
#define BOARD_HUZZAH32 0x34
|
||||
#define BOARD_GENERIC_ESP32 0x35
|
||||
#define BOARD_LORA32_V2_0 0x36
|
||||
#define BOARD_LORA32_V2_1 0x37
|
||||
#define BOARD_LORA32_V1_0 0x39
|
||||
#define BOARD_HELTEC32_V2 0x38
|
||||
#define BOARD_HELTEC32_V3 0x3A
|
||||
#define BOARD_RNODE_NG_20 0x40
|
||||
#define BOARD_RNODE_NG_21 0x41
|
||||
#define BOARD_T3S3 0x42
|
||||
#define BOARD_TECHO 0x43
|
||||
#define BOARD_GENERIC_NRF52 0x50
|
||||
#define BOARD_FREENODE 0x52
|
||||
#define MODEL_FE 0xFE // Homebrew board, max 17dBm output power
|
||||
#define MODEL_FF 0xFF // Homebrew board, max 14dBm output power
|
||||
|
||||
// Displays
|
||||
#define OLED 0x01
|
||||
@ -131,7 +210,6 @@
|
||||
#define DISPLAY OLED
|
||||
#define HAS_PMU true
|
||||
#define HAS_BLUETOOTH true
|
||||
#define HAS_BLE true
|
||||
#define HAS_CONSOLE true
|
||||
#define HAS_SD false
|
||||
#define HAS_EEPROM true
|
||||
@ -139,10 +217,39 @@
|
||||
#define I2C_SCL 22
|
||||
#define PMU_IRQ 35
|
||||
#define INTERFACE_COUNT 1
|
||||
#define HAS_INPUT true
|
||||
const int pin_btn_usr1 = 38;
|
||||
const int pin_led_rx = 2;
|
||||
const int pin_led_tx = 4;
|
||||
|
||||
const uint8_t interfaces[INTERFACE_COUNT] = {SX1262};
|
||||
#if BOARD_VARIANT == MODEL_E4 || BOARD_VARIANT == MODEL_E9
|
||||
const uint8_t interfaces[INTERFACE_COUNT] = {SX127X};
|
||||
const bool interface_cfg[INTERFACE_COUNT][3] = {
|
||||
// SX127X
|
||||
{
|
||||
true, // DEFAULT_SPI
|
||||
false, // HAS_TCXO
|
||||
false // DIO2_AS_RF_SWITCH
|
||||
},
|
||||
};
|
||||
const int8_t interface_pins[INTERFACE_COUNT][10] = {
|
||||
// SX127X
|
||||
{
|
||||
18, // pin_ss
|
||||
-1, // pin_sclk
|
||||
-1, // pin_mosi
|
||||
-1, // pin_miso
|
||||
-1, // pin_busy
|
||||
26, // pin_dio
|
||||
23, // pin_reset
|
||||
-1, // pin_txen
|
||||
-1, // pin_rxen
|
||||
-1 // pin_tcxo_enable
|
||||
}
|
||||
};
|
||||
|
||||
#elif BOARD_VARIANT == MODEL_E3 || BOARD_VARIANT == MODEL_E8
|
||||
const uint8_t interfaces[INTERFACE_COUNT] = {SX126X};
|
||||
const bool interface_cfg[INTERFACE_COUNT][3] = {
|
||||
// SX1262
|
||||
{
|
||||
@ -166,6 +273,7 @@
|
||||
-1 // pin_tcxo_enable
|
||||
}
|
||||
};
|
||||
#endif
|
||||
|
||||
#elif BOARD_MODEL == BOARD_HUZZAH32
|
||||
#define HAS_BLUETOOTH true
|
||||
@ -204,7 +312,6 @@
|
||||
#define HAS_DISPLAY true
|
||||
#define DISPLAY OLED
|
||||
#define HAS_BLUETOOTH true
|
||||
#define HAS_BLE true
|
||||
#define HAS_CONSOLE true
|
||||
#define HAS_EEPROM true
|
||||
#define INTERFACE_COUNT 1
|
||||
@ -248,7 +355,6 @@
|
||||
#define HAS_DISPLAY true
|
||||
#define DISPLAY OLED
|
||||
#define HAS_BLUETOOTH true
|
||||
#define HAS_BLE true
|
||||
#define HAS_CONSOLE true
|
||||
#define HAS_EEPROM true
|
||||
#define INTERFACE_COUNT 1
|
||||
@ -293,7 +399,6 @@
|
||||
#define HAS_DISPLAY true
|
||||
#define DISPLAY OLED
|
||||
#define HAS_BLUETOOTH true
|
||||
#define HAS_BLE true
|
||||
#define HAS_PMU true
|
||||
#define HAS_CONSOLE true
|
||||
#define HAS_EEPROM true
|
||||
@ -367,6 +472,13 @@
|
||||
#define HAS_CONSOLE true
|
||||
#define HAS_EEPROM true
|
||||
#define INTERFACE_COUNT 1
|
||||
#define HAS_INPUT true
|
||||
#define HAS_SLEEP true
|
||||
#define PIN_WAKEUP GPIO_NUM_0
|
||||
#define WAKEUP_LEVEL 0
|
||||
|
||||
const int pin_btn_usr1 = 0;
|
||||
|
||||
#if defined(EXTERNAL_LEDS)
|
||||
const int pin_led_rx = 36;
|
||||
const int pin_led_tx = 37;
|
||||
@ -405,7 +517,8 @@
|
||||
#define HAS_DISPLAY true
|
||||
#define HAS_BLUETOOTH false
|
||||
#define HAS_BLE true
|
||||
#define HAS_CONSOLE false
|
||||
#define HAS_PMU true
|
||||
#define HAS_CONSOLE true
|
||||
#define HAS_EEPROM true
|
||||
#define HAS_INPUT true
|
||||
#define HAS_SLEEP true
|
||||
@ -551,7 +664,6 @@
|
||||
|
||||
#elif BOARD_MODEL == BOARD_T3S3
|
||||
#define IS_ESP32S3 true
|
||||
|
||||
#define HAS_DISPLAY true
|
||||
#define DISPLAY OLED
|
||||
#define HAS_CONSOLE false
|
||||
@ -579,6 +691,7 @@
|
||||
const int SD_MOSI = 11;
|
||||
const int SD_CLK = 14;
|
||||
const int SD_CS = 13;
|
||||
|
||||
#if HAS_NP == false
|
||||
#if defined(EXTERNAL_LEDS)
|
||||
const int pin_led_rx = 37;
|
||||
@ -599,17 +712,6 @@
|
||||
true // DIO2_AS_RF_SWITCH
|
||||
},
|
||||
};
|
||||
#elif BOARD_VARIANT == MODEL_A5 // SX1280 with PA
|
||||
const uint8_t interfaces[INTERFACE_COUNT] = {SX1280};
|
||||
const bool interface_cfg[INTERFACE_COUNT][3] = {
|
||||
// SX1280
|
||||
{
|
||||
false, // DEFAULT_SPI
|
||||
false, // HAS_TCXO
|
||||
false // DIO2_AS_RF_SWITCH
|
||||
},
|
||||
};
|
||||
#endif
|
||||
const uint8_t interface_pins[INTERFACE_COUNT][10] = {
|
||||
// SX1262
|
||||
{
|
||||
@ -625,13 +727,184 @@
|
||||
-1 // pin_tcxo_enable
|
||||
}
|
||||
};
|
||||
#else
|
||||
#error An unsupported ESP32 board was selected. Cannot compile RNode firmware.
|
||||
#endif
|
||||
#elif BOARD_VARIANT == MODEL_AB // SX1280 with PA
|
||||
const uint8_t interfaces[INTERFACE_COUNT] = {SX1280};
|
||||
const bool interface_cfg[INTERFACE_COUNT][3] = {
|
||||
// SX1280
|
||||
{
|
||||
false, // DEFAULT_SPI
|
||||
false, // HAS_TCXO
|
||||
false // DIO2_AS_RF_SWITCH
|
||||
},
|
||||
};
|
||||
const uint8_t interface_pins[INTERFACE_COUNT][10] = {
|
||||
// SX1280
|
||||
{
|
||||
7, // pin_ss
|
||||
5, // pin_sclk
|
||||
6, // pin_mosi
|
||||
3, // pin_miso
|
||||
36, // pin_busy
|
||||
9, // pin_dio
|
||||
8, // pin_reset
|
||||
10, // pin_txen
|
||||
21, // pin_rxen
|
||||
-1 // pin_tcxo_enable
|
||||
}
|
||||
};
|
||||
#endif
|
||||
|
||||
#elif BOARD_MODEL == BOARD_E22_ESP32
|
||||
#define HAS_DISPLAY true
|
||||
#define DISPLAY OLED
|
||||
#define HAS_BLUETOOTH true
|
||||
#define HAS_BLE true
|
||||
#define HAS_CONSOLE true
|
||||
#define HAS_SD false
|
||||
#define HAS_EEPROM true
|
||||
#define I2C_SDA 21
|
||||
#define I2C_SCL 22
|
||||
#define INTERFACE_COUNT 1
|
||||
const int pin_led_rx = 2;
|
||||
const int pin_led_tx = 4;
|
||||
|
||||
const uint8_t interfaces[INTERFACE_COUNT] = {SX1262};
|
||||
const bool interface_cfg[INTERFACE_COUNT][3] = {
|
||||
// SX1262
|
||||
{
|
||||
true, // DEFAULT_SPI
|
||||
true, // HAS_TCXO
|
||||
true // DIO2_AS_RF_SWITCH
|
||||
},
|
||||
};
|
||||
const int8_t interface_pins[INTERFACE_COUNT][10] = {
|
||||
// SX1262
|
||||
{
|
||||
18, // pin_ss
|
||||
5, // pin_sclk
|
||||
27, // pin_mosi
|
||||
19, // pin_miso
|
||||
32, // pin_busy
|
||||
33, // pin_dio
|
||||
23, // pin_reset
|
||||
-1, // pin_txen
|
||||
14, // pin_rxen
|
||||
-1 // pin_tcxo_enable
|
||||
}
|
||||
};
|
||||
|
||||
#elif BOARD_MODEL == BOARD_TDECK
|
||||
#define IS_ESP32S3 true
|
||||
#define MODEM SX1262
|
||||
#define DIO2_AS_RF_SWITCH true
|
||||
#define HAS_BUSY true
|
||||
#define HAS_TCXO true
|
||||
|
||||
#define HAS_DISPLAY false
|
||||
#define HAS_CONSOLE false
|
||||
#define HAS_BLUETOOTH false
|
||||
#define HAS_BLE true
|
||||
#define HAS_PMU true
|
||||
#define HAS_NP false
|
||||
#define HAS_SD false
|
||||
#define HAS_EEPROM true
|
||||
|
||||
#define HAS_INPUT true
|
||||
#define HAS_SLEEP true
|
||||
#define PIN_WAKEUP GPIO_NUM_0
|
||||
#define WAKEUP_LEVEL 0
|
||||
|
||||
const int pin_poweron = 10;
|
||||
const int pin_btn_usr1 = 0;
|
||||
|
||||
const int pin_cs = 9;
|
||||
const int pin_reset = 17;
|
||||
const int pin_sclk = 40;
|
||||
const int pin_mosi = 41;
|
||||
const int pin_miso = 38;
|
||||
const int pin_tcxo_enable = -1;
|
||||
const int pin_dio = 45;
|
||||
const int pin_busy = 13;
|
||||
|
||||
const int SD_MISO = 38;
|
||||
const int SD_MOSI = 41;
|
||||
const int SD_CLK = 40;
|
||||
const int SD_CS = 39;
|
||||
|
||||
const int DISPLAY_DC = 11;
|
||||
const int DISPLAY_CS = 12;
|
||||
const int DISPLAY_MISO = 38;
|
||||
const int DISPLAY_MOSI = 41;
|
||||
const int DISPLAY_CLK = 40;
|
||||
const int DISPLAY_BL_PIN = 42;
|
||||
|
||||
#if HAS_NP == false
|
||||
#if defined(EXTERNAL_LEDS)
|
||||
const int pin_led_rx = 43;
|
||||
const int pin_led_tx = 43;
|
||||
#else
|
||||
const int pin_led_rx = 43;
|
||||
const int pin_led_tx = 43;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#elif BOARD_MODEL == BOARD_TBEAM_S_V1
|
||||
#define IS_ESP32S3 true
|
||||
#define MODEM SX1262
|
||||
#define DIO2_AS_RF_SWITCH true
|
||||
#define HAS_BUSY true
|
||||
#define HAS_TCXO true
|
||||
|
||||
#define HAS_DISPLAY true
|
||||
#define HAS_CONSOLE true
|
||||
#define HAS_BLUETOOTH false
|
||||
#define HAS_BLE true
|
||||
#define HAS_PMU true
|
||||
#define HAS_NP false
|
||||
#define HAS_SD false
|
||||
#define HAS_EEPROM true
|
||||
|
||||
#define HAS_INPUT true
|
||||
#define HAS_SLEEP false
|
||||
|
||||
#define PMU_IRQ 40
|
||||
#define I2C_SCL 41
|
||||
#define I2C_SDA 42
|
||||
|
||||
const int pin_btn_usr1 = 0;
|
||||
|
||||
const int pin_cs = 10;
|
||||
const int pin_reset = 5;
|
||||
const int pin_sclk = 12;
|
||||
const int pin_mosi = 11;
|
||||
const int pin_miso = 13;
|
||||
const int pin_tcxo_enable = -1;
|
||||
const int pin_dio = 1;
|
||||
const int pin_busy = 4;
|
||||
|
||||
const int SD_MISO = 37;
|
||||
const int SD_MOSI = 35;
|
||||
const int SD_CLK = 36;
|
||||
const int SD_CS = 47;
|
||||
|
||||
const int IMU_CS = 34;
|
||||
|
||||
#if HAS_NP == false
|
||||
#if defined(EXTERNAL_LEDS)
|
||||
const int pin_led_rx = 43;
|
||||
const int pin_led_tx = 43;
|
||||
#else
|
||||
const int pin_led_rx = 43;
|
||||
const int pin_led_tx = 43;
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
#elif MCU_VARIANT == MCU_NRF52
|
||||
#if BOARD_MODEL == BOARD_TECHO
|
||||
#define VALIDATE_FIRMWARE false
|
||||
#define HAS_INPUT true
|
||||
//#define GPS_BAUD_RATE 115200
|
||||
//#define PIN_GPS_TX 41
|
||||
//#define PIN_GPS_RX 40
|
||||
@ -639,17 +912,18 @@
|
||||
#define EEPROM_OFFSET EEPROM_SIZE-EEPROM_RESERVED
|
||||
//#define HAS_EEPROM true
|
||||
//#define HAS_SD true
|
||||
//#define HAS_DISPLAY true
|
||||
#define HAS_DISPLAY true
|
||||
#define DISPLAY EINK_BW
|
||||
#define DISPLAY_MODEL GxEPD2_154_D67
|
||||
//#define HAS_CONSOLE true
|
||||
//#define HAS_TXCO true
|
||||
//#define DISPLAY EINK_BW
|
||||
//#define HAS_BLE true
|
||||
//#define HAS_PMU true
|
||||
#define CONFIG_UART_BUFFER_SIZE 40000
|
||||
#define CONFIG_QUEUE_0_SIZE 6144
|
||||
#define CONFIG_QUEUE_MAX_LENGTH 200
|
||||
#define BLE_MANUFACTURER "LilyGO"
|
||||
#define BLE_MODEL "T-Echo"
|
||||
//#define BLE_MANUFACTURER "LilyGO"
|
||||
//#define BLE_MODEL "T-Echo"
|
||||
#define INTERFACE_COUNT 1
|
||||
//#define I2C_SDA 26
|
||||
//#define I2C_SCL 27
|
||||
@ -686,10 +960,17 @@
|
||||
const int pin_disp_reset = 2;
|
||||
const int pin_disp_busy = 3;
|
||||
const int pin_disp_en = 43;
|
||||
const int pin_disp_sck = 31;
|
||||
const int pin_disp_mosi = 29;
|
||||
const int pin_disp_miso = -1;
|
||||
|
||||
#define HAS_BACKLIGHT true
|
||||
const int pin_btn_usr1 = 42;
|
||||
const int pin_backlight = 43;
|
||||
|
||||
const int pin_led_rx = LED_BLUE;
|
||||
const int pin_led_tx = LED_RED;
|
||||
#elif BOARD_MODEL == BOARD_FREENODE
|
||||
#elif BOARD_MODEL == BOARD_OPENCOM_XL
|
||||
#define HAS_EEPROM false
|
||||
#define HAS_DISPLAY true
|
||||
#define DISPLAY EINK_BW
|
||||
@ -699,16 +980,14 @@
|
||||
#define HAS_PMU true
|
||||
#define HAS_NP false
|
||||
#define HAS_SD false
|
||||
#define CONFIG_UART_BUFFER_SIZE 40000
|
||||
#define CONFIG_QUEUE_0_SIZE 6144
|
||||
#define CONFIG_QUEUE_1_SIZE 20000
|
||||
#define CONFIG_QUEUE_MAX_LENGTH 200
|
||||
#define EEPROM_SIZE 296
|
||||
#define EEPROM_OFFSET EEPROM_SIZE-EEPROM_RESERVED
|
||||
#define BLE_MANUFACTURER "RAK Wireless"
|
||||
#define BLE_MODEL "RAK4640"
|
||||
|
||||
#define HAS_BUZZER true
|
||||
#define HAS_BUZZER false
|
||||
#define PIN_BUZZER WB_IO2
|
||||
|
||||
// todo, I would much rather these be in Buzzer.h
|
||||
@ -718,14 +997,15 @@
|
||||
#define TX_HI_TONE 550
|
||||
#define MAX_BUZZER_DELAY 100
|
||||
|
||||
#define HAS_BUZZER_CTRL true
|
||||
#define HAS_BUZZER_CTRL false
|
||||
|
||||
#define HAS_INPUT true
|
||||
#define HAS_INPUT false
|
||||
#define PIN_BUTTON WB_SW1
|
||||
|
||||
#define INTERFACE_COUNT 2
|
||||
|
||||
#define CONFIG_QUEUE_1_SIZE 40000
|
||||
#define CONFIG_UART_BUFFER_SIZE 40000 // \todo, does it have to be this big?
|
||||
|
||||
// first interface in list is the primary
|
||||
const uint8_t interfaces[INTERFACE_COUNT] = {SX126X, SX128X};
|
||||
@ -778,6 +1058,7 @@
|
||||
const int pin_disp_busy = WB_IO4;
|
||||
const int pin_disp_en = WB_IO2;
|
||||
|
||||
const int pin_btn_usr1 = 9;
|
||||
const int pin_led_rx = LED_BLUE;
|
||||
const int pin_led_tx = LED_GREEN;
|
||||
#else
|
||||
|
23
Config.h
23
Config.h
@ -1,4 +1,4 @@
|
||||
// Copyright (C) 2023, Mark Qvist
|
||||
// Copyright (C) 2024, Mark Qvist
|
||||
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
@ -20,7 +20,7 @@
|
||||
#define CONFIG_H
|
||||
|
||||
#define MAJ_VERS 0x01
|
||||
#define MIN_VERS 0x4a
|
||||
#define MIN_VERS 0x4b
|
||||
|
||||
#define MODE_HOST 0x11
|
||||
#define MODE_TNC 0x12
|
||||
@ -65,7 +65,6 @@
|
||||
// packet RSSI register
|
||||
const int rssi_offset = 157;
|
||||
|
||||
|
||||
// Default LoRa settings
|
||||
const int lora_rx_turnaround_ms = 66;
|
||||
const int lora_post_tx_yield_slots = 6;
|
||||
@ -78,10 +77,10 @@
|
||||
bool pmu_ready = false;
|
||||
bool promisc = false;
|
||||
bool implicit = false;
|
||||
bool memory_low = false;
|
||||
uint8_t implicit_l = 0;
|
||||
|
||||
volatile bool packet_ready = false;
|
||||
volatile uint8_t packet_interface = 0xFF;
|
||||
uint8_t packet_interface = 0xFF;
|
||||
|
||||
uint8_t op_mode = MODE_HOST;
|
||||
uint8_t model = 0x00;
|
||||
@ -90,7 +89,7 @@
|
||||
int last_rssi = -292;
|
||||
uint8_t last_rssi_raw = 0x00;
|
||||
uint8_t last_snr_raw = 0x80;
|
||||
uint8_t seq = 0xFF;
|
||||
uint8_t seq[INTERFACE_COUNT];
|
||||
uint16_t read_len = 0;
|
||||
|
||||
bool serial_in_frame = false;
|
||||
@ -115,9 +114,10 @@
|
||||
unsigned long last_rx = 0;
|
||||
|
||||
// Power management
|
||||
#define BATTERY_STATE_UNKNOWN 0x00
|
||||
#define BATTERY_STATE_DISCHARGING 0x01
|
||||
#define BATTERY_STATE_CHARGING 0x02
|
||||
#define BATTERY_STATE_CHARGED 0x03
|
||||
#define BATTERY_STATE_CHARGING 0x02
|
||||
#define BATTERY_STATE_CHARGED 0x03
|
||||
bool battery_installed = false;
|
||||
bool battery_indeterminate = false;
|
||||
bool external_power = false;
|
||||
@ -127,6 +127,7 @@
|
||||
uint8_t battery_state = 0x00;
|
||||
uint8_t display_intensity = 0xFF;
|
||||
uint8_t display_addr = 0xFF;
|
||||
bool display_blanking_enabled = false;
|
||||
bool display_diagnostics = true;
|
||||
bool device_init_done = false;
|
||||
bool eeprom_ok = false;
|
||||
@ -134,9 +135,9 @@
|
||||
|
||||
// Boot flags
|
||||
#define START_FROM_BOOTLOADER 0x01
|
||||
#define START_FROM_POWERON 0x02
|
||||
#define START_FROM_BROWNOUT 0x03
|
||||
#define START_FROM_JTAG 0x04
|
||||
#define START_FROM_POWERON 0x02
|
||||
#define START_FROM_BROWNOUT 0x03
|
||||
#define START_FROM_JTAG 0x04
|
||||
|
||||
// Subinterfaces
|
||||
// select interface 0 by default
|
||||
|
@ -1,4 +1,4 @@
|
||||
// Copyright (C) 2023, Mark Qvist
|
||||
// Copyright (C) 2024, Mark Qvist
|
||||
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
|
@ -21,7 +21,7 @@ pages-debug:
|
||||
|
||||
sourcepack:
|
||||
@echo Packing firmware sources...
|
||||
zip --junk-paths -r build/pkg/rnode_firmware.zip ../arduino-cli.yaml ../Bluetooth.h ../Boards.h ../Config.h ../Console.h ../Device.h ../Display.h ../Framing.h ../Graphics.h ../Input.h ../LICENSE ../Makefile ../MD5.cpp ../MD5.h ../Modem.h ../partition_hashes ../Power.h ../README.md ../release_hashes.py ../RNode_Firmware_CE.ino ../ROM.h ../sx126x.cpp ../sx126x.h ../sx127x.cpp ../sx127x.h ../sx128x.cpp ../sx128x.h ../Utilities.h
|
||||
zip --junk-paths -r build/pkg/rnode_firmware.zip ../arduino-cli.yaml ../src/ble/BLESerial.cpp ../src/ble/BLESerial.h ../Bluetooth.h ../Boards.h ../Config.h ../Console.h ../Device.h ../Display.h ../Framing.h ../Graphics.h .../Input.h ../Interfaces.h ../LICENSE ../Makefile ../src/misc/FIFOBuffer.c ../src/misc/FIFOBuffer.h ../src/misc/MD5.cpp ../src/misc/MD5.h ../partition_hashes ../Power.h ../README.md ../release_hashes.py ../RNode_Firmware_CE.ino ../ROM.h ../Radio.cpp ../Radio.hpp ../Utilities.h ../esp32_btbufs.py
|
||||
|
||||
data:
|
||||
@echo Including assets...
|
||||
|
@ -4,9 +4,9 @@ import sys
|
||||
import shutil
|
||||
|
||||
packages = {
|
||||
"rns": "rns-0.7.5-py3-none-any.whl",
|
||||
"nomadnet": "nomadnet-0.4.9-py3-none-any.whl",
|
||||
"lxmf": "lxmf-0.4.3-py3-none-any.whl",
|
||||
"rns": "rns-0.8.2-py3-none-any.whl",
|
||||
"nomadnet": "nomadnet-0.5.4-py3-none-any.whl",
|
||||
"lxmf": "lxmf-0.5.5-py3-none-any.whl",
|
||||
"rnsh": "rnsh-0.1.4-py3-none-any.whl",
|
||||
}
|
||||
|
||||
@ -174,26 +174,34 @@ mf.write(help_redirect)
|
||||
mf.close()
|
||||
|
||||
def optimise_manual(path):
|
||||
pm = 110
|
||||
pm = 60
|
||||
scale_imgs = [
|
||||
("_images/board_rnodev2.png", pm),
|
||||
("_images/board_rnode.png", pm),
|
||||
("_images/board_heltec32.png", pm),
|
||||
("_images/board_heltec32v20.png", pm),
|
||||
("_images/board_heltec32v30.png", pm),
|
||||
("_images/board_t3v21.png", pm),
|
||||
("_images/board_t3v20.png", pm),
|
||||
("_images/sideband_devices.webp", pm),
|
||||
("_images/board_t3v10.png", pm),
|
||||
("_images/board_t3s3.png", pm),
|
||||
("_images/board_tbeam.png", pm),
|
||||
("_images/board_tdeck.png", pm),
|
||||
("_images/board_rak4631.png", pm),
|
||||
("_images/board_tbeam_supreme.png", pm),
|
||||
("_images/sideband_devices.webp", pm),
|
||||
("_images/nomadnet_3.png", pm),
|
||||
("_images/meshchat_1.webp", pm),
|
||||
("_images/radio_is5ac.png", pm),
|
||||
("_images/radio_rblhg5.png", pm),
|
||||
("_static/rns_logo_512.png", 256),
|
||||
("../images/bg_h_1.webp", pm),
|
||||
]
|
||||
|
||||
import subprocess
|
||||
import shlex
|
||||
for i,s in scale_imgs:
|
||||
fp = path+"/"+i
|
||||
resize = "convert "+fp+" -resize "+str(s)+" "+fp
|
||||
resize = "convert "+fp+" -quality 25 -resize "+str(s)+" "+fp
|
||||
print(resize)
|
||||
subprocess.call(shlex.split(resize), stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
|
||||
|
||||
@ -205,6 +213,7 @@ def optimise_manual(path):
|
||||
"_static/scripts/furo.js.map",
|
||||
"_static/jquery-3.6.0.js",
|
||||
"_static/jquery.js",
|
||||
"static/underscore-1.13.1.js",
|
||||
"_static/_sphinx_javascript_frameworks_compat.js",
|
||||
"_static/scripts/furo.js.LICENSE.txt",
|
||||
"_static/styles/furo-extensions.css.map",
|
||||
|
5
Device.h
5
Device.h
@ -1,4 +1,4 @@
|
||||
// Copyright (C) 2023, Mark Qvist
|
||||
// Copyright (C) 2024, Mark Qvist
|
||||
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
@ -296,7 +296,8 @@ bool device_init() {
|
||||
}
|
||||
#else
|
||||
// Skip hash comparison and checking BT
|
||||
return true;
|
||||
device_init_done = true;
|
||||
return device_init_done;
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
12
Framing.h
12
Framing.h
@ -1,4 +1,4 @@
|
||||
// Copyright (C) 2023, Mark Qvist
|
||||
// Copyright (C) 2024, Mark Qvist
|
||||
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
@ -53,6 +53,8 @@
|
||||
#define CMD_FB_READL 0x44
|
||||
#define CMD_DISP_INT 0x45
|
||||
#define CMD_DISP_ADDR 0x63
|
||||
#define CMD_DISP_BLNK 0x64
|
||||
#define CMD_NP_INT 0x65
|
||||
#define CMD_BT_CTRL 0x46
|
||||
#define CMD_BT_PIN 0x62
|
||||
|
||||
@ -81,7 +83,7 @@
|
||||
#define CMD_INT1_DATA 0x10
|
||||
#define CMD_INT2_DATA 0x20
|
||||
#define CMD_INT3_DATA 0x70
|
||||
#define CMD_INT4_DATA 0x80
|
||||
#define CMD_INT4_DATA 0x75
|
||||
#define CMD_INT5_DATA 0x90
|
||||
#define CMD_INT6_DATA 0xA0
|
||||
#define CMD_INT7_DATA 0xB0
|
||||
@ -93,8 +95,8 @@
|
||||
#define CMD_SEL_INT0 0x1E
|
||||
#define CMD_SEL_INT1 0x1F
|
||||
#define CMD_SEL_INT2 0x2F
|
||||
#define CMD_SEL_INT3 0x7F
|
||||
#define CMD_SEL_INT4 0x8F
|
||||
#define CMD_SEL_INT3 0x74
|
||||
#define CMD_SEL_INT4 0x7F
|
||||
#define CMD_SEL_INT5 0x9F
|
||||
#define CMD_SEL_INT6 0xAF
|
||||
#define CMD_SEL_INT7 0xBF
|
||||
@ -119,6 +121,8 @@
|
||||
#define ERROR_TXFAILED 0x02
|
||||
#define ERROR_EEPROM_LOCKED 0x03
|
||||
#define ERROR_QUEUE_FULL 0x04
|
||||
#define ERROR_MEMORY_LOW 0x05
|
||||
#define ERROR_MODEM_TIMEOUT 0x06
|
||||
|
||||
// Serial framing variables
|
||||
size_t frame_len;
|
||||
|
794
Graphics.h
794
Graphics.h
@ -1,4 +1,4 @@
|
||||
// Copyright (C) 2023, Mark Qvist
|
||||
// Copyright (C) 2024, Mark Qvist
|
||||
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
@ -13,402 +13,7 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
#if DISP_H == UNSCALED_MAX
|
||||
// use 64px wide graphics
|
||||
|
||||
const unsigned char bm_cable [] PROGMEM = {
|
||||
0x00, 0x00, 0x00, 0x1c, 0x00, 0x38, 0x07, 0xfc, 0x08, 0x38, 0x10, 0x1c, 0x10, 0x00, 0x08, 0x00,
|
||||
0x07, 0xc0, 0x00, 0x20, 0x00, 0x10, 0x00, 0x10, 0x00, 0x20, 0x07, 0xc0, 0x08, 0x00, 0x10, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x04, 0x80, 0x04, 0x43, 0x08, 0x46,
|
||||
0xf1, 0x8f, 0x02, 0x16, 0x02, 0x23, 0x01, 0x20, 0x00, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
|
||||
};
|
||||
|
||||
const unsigned char bm_bt [] PROGMEM = {
|
||||
0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x11, 0x40, 0x00, 0x00, 0x05, 0x10, 0x00, 0x00, 0x01, 0x40,
|
||||
0x00, 0x00, 0x01, 0x40, 0x00, 0x00, 0x05, 0x10, 0x00, 0x00, 0x11, 0x40, 0x00, 0x00, 0x01, 0x00,
|
||||
0x00, 0x00, 0x01, 0x00, 0x01, 0x80, 0x01, 0x40, 0x09, 0x20, 0x05, 0x10, 0x03, 0x20, 0x01, 0x40,
|
||||
0x01, 0x80, 0x01, 0x40, 0x03, 0x20, 0x05, 0x10, 0x09, 0x20, 0x01, 0x40, 0x01, 0x80, 0x01, 0x00,
|
||||
0x00, 0x00, 0x01, 0x00, 0x01, 0x80, 0x01, 0x40, 0x09, 0x20, 0x05, 0x10, 0x03, 0x20, 0x01, 0x40,
|
||||
0x29, 0x94, 0x01, 0x40, 0x03, 0x20, 0x05, 0x10, 0x09, 0x20, 0x01, 0x40, 0x01, 0x80, 0x01, 0x00,
|
||||
0x00, 0x00, 0x01, 0x00, 0x01, 0x80, 0x01, 0x40, 0x09, 0x20, 0x05, 0x10, 0x03, 0x20, 0x11, 0x48,
|
||||
0x29, 0x94, 0x11, 0x48, 0x03, 0x20, 0x05, 0x10, 0x09, 0x20, 0x01, 0x40, 0x01, 0x80, 0x01, 0x00
|
||||
};
|
||||
|
||||
const unsigned char bm_rf [] PROGMEM = {
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4e, 0xc4,
|
||||
0x4a, 0xaa, 0x4a, 0xce, 0x6e, 0xaa, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x07, 0xe0, 0x08, 0x10, 0x13, 0xc8, 0x04, 0x20, 0x01, 0x80, 0x00, 0x00, 0x4e, 0xc4,
|
||||
0x4a, 0xaa, 0x4a, 0xce, 0x6e, 0xaa, 0x00, 0x00, 0x01, 0x80, 0x04, 0x20, 0x03, 0xc0, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x71, 0x4e,
|
||||
0x31, 0x48, 0x61, 0xca, 0x74, 0x4e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x07, 0xe0, 0x08, 0x10, 0x13, 0xc8, 0x04, 0x20, 0x01, 0x80, 0x00, 0x00, 0x71, 0x4e,
|
||||
0x31, 0x48, 0x61, 0xca, 0x74, 0x4e, 0x00, 0x00, 0x01, 0x80, 0x04, 0x20, 0x03, 0xc0, 0x00, 0x00
|
||||
};
|
||||
|
||||
const unsigned char bm_boot [] PROGMEM = {
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xfc, 0x38, 0x66, 0x67, 0x1c, 0x3f, 0xff, 0xff, 0xfc, 0x99, 0xe6, 0x66, 0x4c, 0xff, 0xff,
|
||||
0xff, 0xfc, 0x98, 0x70, 0xe6, 0x7c, 0x3f, 0xff, 0xff, 0xfc, 0x99, 0xf0, 0xe6, 0x4c, 0xff, 0xff,
|
||||
0xff, 0xfc, 0x38, 0x79, 0xe7, 0x1c, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0x0c, 0x38, 0xe1, 0xc3, 0x33, 0x38, 0x7f, 0xfe, 0x7e, 0x72, 0x64, 0xe7, 0x31, 0x33, 0xff,
|
||||
0xff, 0x1e, 0x70, 0x61, 0xe7, 0x30, 0x32, 0x7f, 0xff, 0xce, 0x72, 0x61, 0xe7, 0x32, 0x32, 0x7f,
|
||||
0xfe, 0x1e, 0x72, 0x64, 0xe7, 0x33, 0x38, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
|
||||
};
|
||||
|
||||
const unsigned char bm_no_radio [] PROGMEM = {
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc3, 0xc7, 0x0e, 0x71, 0xfc, 0xce, 0x38, 0x7f,
|
||||
0xc9, 0x93, 0x26, 0x64, 0xfc, 0x4c, 0x9c, 0xff, 0xc3, 0x83, 0x26, 0x64, 0xfc, 0x0c, 0x9c, 0xff,
|
||||
0xc3, 0x93, 0x26, 0x64, 0xfc, 0x8c, 0x9c, 0xff, 0xc9, 0x93, 0x0e, 0x71, 0xfc, 0xce, 0x3c, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc3, 0x8e, 0x4c, 0xcc, 0x3f, 0xff, 0xfc, 0xff,
|
||||
0xcf, 0x26, 0x4c, 0x4c, 0x9f, 0xff, 0xfb, 0x7f, 0xc3, 0x26, 0x4c, 0x0c, 0x9f, 0xff, 0xfb, 0x7f,
|
||||
0xcf, 0x26, 0x4c, 0x8c, 0x9f, 0xff, 0xf7, 0xbf, 0xcf, 0x8f, 0x1c, 0xcc, 0x3f, 0xff, 0xf4, 0xbf,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xec, 0xdf, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xec, 0xdf,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xdc, 0xef, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xdc, 0xef,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xbf, 0xf7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xbc, 0xf7,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7c, 0xfb, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f, 0xfb,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0x07, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
|
||||
};
|
||||
|
||||
const unsigned char bm_hwfail [] PROGMEM = {
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe4, 0xe3, 0x87, 0x0e |