Compare commits
20 Commits
meshcore-e
...
v0.1.1
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
eae36780fa | ||
|
|
b05c97c244 | ||
|
|
7afcf1c3a2 | ||
|
|
bf8c43b3ad | ||
|
|
012217dd72 | ||
|
|
745f71e147 | ||
|
|
0e78d85a5a | ||
|
|
4df9977e0f | ||
|
|
92df37e821 | ||
|
|
37bd05cff2 | ||
|
|
27b030c9a2 | ||
|
|
8989a4503a | ||
|
|
eb4fa032ff | ||
|
|
e563529cc5 | ||
|
|
09a20d72e7 | ||
|
|
14f00fe688 | ||
|
|
ce3b6e67f9 | ||
|
|
3a497a4b99 | ||
|
|
5871c69f6f | ||
|
|
802de27e03 |
24
build.sh
24
build.sh
@@ -29,20 +29,6 @@ $ sh build.sh build-repeater-firmwares
|
|||||||
|
|
||||||
Build all chat room server firmwares
|
Build all chat room server firmwares
|
||||||
$ sh build.sh build-room-server-firmwares
|
$ sh build.sh build-room-server-firmwares
|
||||||
|
|
||||||
Environment Variables:
|
|
||||||
DISABLE_DEBUG=1: Disables all debug logging flags (MESH_DEBUG, MESH_PACKET_LOGGING, etc.)
|
|
||||||
If not set, debug flags from variant platformio.ini files are used.
|
|
||||||
|
|
||||||
Examples:
|
|
||||||
Build without debug logging:
|
|
||||||
$ export FIRMWARE_VERSION=v1.0.0
|
|
||||||
$ export DISABLE_DEBUG=1
|
|
||||||
$ sh build.sh build-firmware RAK_4631_repeater
|
|
||||||
|
|
||||||
Build with debug logging (default, uses flags from variant files):
|
|
||||||
$ export FIRMWARE_VERSION=v1.0.0
|
|
||||||
$ sh build.sh build-firmware RAK_4631_repeater
|
|
||||||
EOF
|
EOF
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -82,13 +68,6 @@ get_pio_envs_ending_with_string() {
|
|||||||
done
|
done
|
||||||
}
|
}
|
||||||
|
|
||||||
# disable all debug logging flags if DISABLE_DEBUG=1 is set
|
|
||||||
disable_debug_flags() {
|
|
||||||
if [ "$DISABLE_DEBUG" == "1" ]; then
|
|
||||||
export PLATFORMIO_BUILD_FLAGS="${PLATFORMIO_BUILD_FLAGS} -UMESH_DEBUG -UBLE_DEBUG_LOGGING -UWIFI_DEBUG_LOGGING -UBRIDGE_DEBUG -UGPS_NMEA_DEBUG -UCORE_DEBUG_LEVEL -UESPNOW_DEBUG_LOGGING -UDEBUG_RP2040_WIRE -UDEBUG_RP2040_SPI -UDEBUG_RP2040_CORE -UDEBUG_RP2040_PORT -URADIOLIB_DEBUG_SPI -UCFG_DEBUG -URADIOLIB_DEBUG_BASIC -URADIOLIB_DEBUG_PROTOCOL"
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
# build firmware for the provided pio env in $1
|
# build firmware for the provided pio env in $1
|
||||||
build_firmware() {
|
build_firmware() {
|
||||||
|
|
||||||
@@ -115,9 +94,6 @@ build_firmware() {
|
|||||||
# add firmware version info to end of existing platformio build flags in environment vars
|
# add firmware version info to end of existing platformio build flags in environment vars
|
||||||
export PLATFORMIO_BUILD_FLAGS="${PLATFORMIO_BUILD_FLAGS} -DFIRMWARE_BUILD_DATE='\"${FIRMWARE_BUILD_DATE}\"' -DFIRMWARE_VERSION='\"${FIRMWARE_VERSION_STRING}\"'"
|
export PLATFORMIO_BUILD_FLAGS="${PLATFORMIO_BUILD_FLAGS} -DFIRMWARE_BUILD_DATE='\"${FIRMWARE_BUILD_DATE}\"' -DFIRMWARE_VERSION='\"${FIRMWARE_VERSION_STRING}\"'"
|
||||||
|
|
||||||
# disable debug flags if requested
|
|
||||||
disable_debug_flags
|
|
||||||
|
|
||||||
# build firmware target
|
# build firmware target
|
||||||
pio run -e $1
|
pio run -e $1
|
||||||
|
|
||||||
|
|||||||
@@ -103,9 +103,7 @@ Request type
|
|||||||
| `0x02` | keepalive | (deprecated) |
|
| `0x02` | keepalive | (deprecated) |
|
||||||
| `0x03` | get telemetry data | TODO |
|
| `0x03` | get telemetry data | TODO |
|
||||||
| `0x04` | get min,max,avg data | sensor nodes - get min, max, average for given time span |
|
| `0x04` | get min,max,avg data | sensor nodes - get min, max, average for given time span |
|
||||||
| `0x05` | get access list | get node's approved access list |
|
| `0x05` | get access list | get node's approved access list |
|
||||||
| `0x06` | get neighbors | get repeater node's neighbors |
|
|
||||||
| `0x07` | get owner info | get repeater firmware-ver/name/owner info |
|
|
||||||
|
|
||||||
### Get stats
|
### Get stats
|
||||||
|
|
||||||
@@ -134,27 +132,6 @@ Gets information about the node, possibly including the following:
|
|||||||
|
|
||||||
Request data about sensors on the node, including battery level.
|
Request data about sensors on the node, including battery level.
|
||||||
|
|
||||||
### Get Telemetry
|
|
||||||
|
|
||||||
TODO
|
|
||||||
|
|
||||||
### Get Min/Max/Ave (Sensor nodes)
|
|
||||||
|
|
||||||
TODO
|
|
||||||
|
|
||||||
### Get Access List
|
|
||||||
|
|
||||||
TODO
|
|
||||||
|
|
||||||
### Get Neighors
|
|
||||||
|
|
||||||
TODO
|
|
||||||
|
|
||||||
### Get Owner Info
|
|
||||||
|
|
||||||
TODO
|
|
||||||
|
|
||||||
|
|
||||||
## Response
|
## Response
|
||||||
|
|
||||||
| Field | Size (bytes) | Description |
|
| Field | Size (bytes) | Description |
|
||||||
@@ -202,34 +179,6 @@ txt_type
|
|||||||
| timestamp | 4 | sender time (unix timestamp) |
|
| timestamp | 4 | sender time (unix timestamp) |
|
||||||
| password | rest of message | password for repeater/sensor |
|
| password | rest of message | password for repeater/sensor |
|
||||||
|
|
||||||
## Repeater - Regions request
|
|
||||||
|
|
||||||
| Field | Size (bytes) | Description |
|
|
||||||
|----------------|-----------------|-------------------------------------------------------------------------------|
|
|
||||||
| timestamp | 4 | sender time (unix timestamp) |
|
|
||||||
| req type | 1 | 0x01 (request sub type) |
|
|
||||||
| reply path len | 1 | path len for reply |
|
|
||||||
| reply path | (variable) | reply path |
|
|
||||||
|
|
||||||
## Repeater - Owner info request
|
|
||||||
|
|
||||||
| Field | Size (bytes) | Description |
|
|
||||||
|----------------|-----------------|-------------------------------------------------------------------------------|
|
|
||||||
| timestamp | 4 | sender time (unix timestamp) |
|
|
||||||
| req type | 1 | 0x02 (request sub type) |
|
|
||||||
| reply path len | 1 | path len for reply |
|
|
||||||
| reply path | (variable) | reply path |
|
|
||||||
|
|
||||||
## Repeater - Clock and status request
|
|
||||||
|
|
||||||
| Field | Size (bytes) | Description |
|
|
||||||
|----------------|-----------------|-------------------------------------------------------------------------------|
|
|
||||||
| timestamp | 4 | sender time (unix timestamp) |
|
|
||||||
| req type | 1 | 0x03 (request sub type) |
|
|
||||||
| reply path len | 1 | path len for reply |
|
|
||||||
| reply path | (variable) | reply path |
|
|
||||||
|
|
||||||
|
|
||||||
# Group text message / datagram
|
# Group text message / datagram
|
||||||
|
|
||||||
| Field | Size (bytes) | Description |
|
| Field | Size (bytes) | Description |
|
||||||
|
|||||||
@@ -227,7 +227,6 @@ void DataStore::loadPrefsInt(const char *filename, NodePrefs& _prefs, double& no
|
|||||||
file.read((uint8_t *)&_prefs.buzzer_quiet, sizeof(_prefs.buzzer_quiet)); // 84
|
file.read((uint8_t *)&_prefs.buzzer_quiet, sizeof(_prefs.buzzer_quiet)); // 84
|
||||||
file.read((uint8_t *)&_prefs.gps_enabled, sizeof(_prefs.gps_enabled)); // 85
|
file.read((uint8_t *)&_prefs.gps_enabled, sizeof(_prefs.gps_enabled)); // 85
|
||||||
file.read((uint8_t *)&_prefs.gps_interval, sizeof(_prefs.gps_interval)); // 86
|
file.read((uint8_t *)&_prefs.gps_interval, sizeof(_prefs.gps_interval)); // 86
|
||||||
file.read((uint8_t *)&_prefs.autoadd_config, sizeof(_prefs.autoadd_config)); // 87
|
|
||||||
|
|
||||||
file.close();
|
file.close();
|
||||||
}
|
}
|
||||||
@@ -262,7 +261,6 @@ void DataStore::savePrefs(const NodePrefs& _prefs, double node_lat, double node_
|
|||||||
file.write((uint8_t *)&_prefs.buzzer_quiet, sizeof(_prefs.buzzer_quiet)); // 84
|
file.write((uint8_t *)&_prefs.buzzer_quiet, sizeof(_prefs.buzzer_quiet)); // 84
|
||||||
file.write((uint8_t *)&_prefs.gps_enabled, sizeof(_prefs.gps_enabled)); // 85
|
file.write((uint8_t *)&_prefs.gps_enabled, sizeof(_prefs.gps_enabled)); // 85
|
||||||
file.write((uint8_t *)&_prefs.gps_interval, sizeof(_prefs.gps_interval)); // 86
|
file.write((uint8_t *)&_prefs.gps_interval, sizeof(_prefs.gps_interval)); // 86
|
||||||
file.write((uint8_t *)&_prefs.autoadd_config, sizeof(_prefs.autoadd_config)); // 87
|
|
||||||
|
|
||||||
file.close();
|
file.close();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -53,9 +53,6 @@
|
|||||||
#define CMD_SET_FLOOD_SCOPE 54 // v8+
|
#define CMD_SET_FLOOD_SCOPE 54 // v8+
|
||||||
#define CMD_SEND_CONTROL_DATA 55 // v8+
|
#define CMD_SEND_CONTROL_DATA 55 // v8+
|
||||||
#define CMD_GET_STATS 56 // v8+, second byte is stats type
|
#define CMD_GET_STATS 56 // v8+, second byte is stats type
|
||||||
#define CMD_SEND_ANON_REQ 57
|
|
||||||
#define CMD_SET_AUTOADD_CONFIG 58
|
|
||||||
#define CMD_GET_AUTOADD_CONFIG 59
|
|
||||||
|
|
||||||
// Stats sub-types for CMD_GET_STATS
|
// Stats sub-types for CMD_GET_STATS
|
||||||
#define STATS_TYPE_CORE 0
|
#define STATS_TYPE_CORE 0
|
||||||
@@ -87,7 +84,6 @@
|
|||||||
#define RESP_CODE_ADVERT_PATH 22
|
#define RESP_CODE_ADVERT_PATH 22
|
||||||
#define RESP_CODE_TUNING_PARAMS 23
|
#define RESP_CODE_TUNING_PARAMS 23
|
||||||
#define RESP_CODE_STATS 24 // v8+, second byte is stats type
|
#define RESP_CODE_STATS 24 // v8+, second byte is stats type
|
||||||
#define RESP_CODE_AUTOADD_CONFIG 25
|
|
||||||
|
|
||||||
#define SEND_TIMEOUT_BASE_MILLIS 500
|
#define SEND_TIMEOUT_BASE_MILLIS 500
|
||||||
#define FLOOD_SEND_TIMEOUT_FACTOR 16.0f
|
#define FLOOD_SEND_TIMEOUT_FACTOR 16.0f
|
||||||
@@ -113,8 +109,6 @@
|
|||||||
#define PUSH_CODE_BINARY_RESPONSE 0x8C
|
#define PUSH_CODE_BINARY_RESPONSE 0x8C
|
||||||
#define PUSH_CODE_PATH_DISCOVERY_RESPONSE 0x8D
|
#define PUSH_CODE_PATH_DISCOVERY_RESPONSE 0x8D
|
||||||
#define PUSH_CODE_CONTROL_DATA 0x8E // v8+
|
#define PUSH_CODE_CONTROL_DATA 0x8E // v8+
|
||||||
#define PUSH_CODE_CONTACT_DELETED 0x8F // used to notify client app of deleted contact when overwriting oldest
|
|
||||||
#define PUSH_CODE_CONTACTS_FULL 0x90 // used to notify client app that contacts storage is full
|
|
||||||
|
|
||||||
#define ERR_CODE_UNSUPPORTED_CMD 1
|
#define ERR_CODE_UNSUPPORTED_CMD 1
|
||||||
#define ERR_CODE_NOT_FOUND 2
|
#define ERR_CODE_NOT_FOUND 2
|
||||||
@@ -125,15 +119,6 @@
|
|||||||
|
|
||||||
#define MAX_SIGN_DATA_LEN (8 * 1024) // 8K
|
#define MAX_SIGN_DATA_LEN (8 * 1024) // 8K
|
||||||
|
|
||||||
// Auto-add config bitmask
|
|
||||||
// Bit 0: If set, overwrite oldest non-favourite contact when contacts file is full
|
|
||||||
// Bits 1-4: these indicate which contact types to auto-add when manual_contact_mode = 0x01
|
|
||||||
#define AUTO_ADD_OVERWRITE_OLDEST (1 << 0) // 0x01 - overwrite oldest non-favourite when full
|
|
||||||
#define AUTO_ADD_CHAT (1 << 1) // 0x02 - auto-add Chat (Companion) (ADV_TYPE_CHAT)
|
|
||||||
#define AUTO_ADD_REPEATER (1 << 2) // 0x04 - auto-add Repeater (ADV_TYPE_REPEATER)
|
|
||||||
#define AUTO_ADD_ROOM_SERVER (1 << 3) // 0x08 - auto-add Room Server (ADV_TYPE_ROOM)
|
|
||||||
#define AUTO_ADD_SENSOR (1 << 4) // 0x10 - auto-add Sensor (ADV_TYPE_SENSOR)
|
|
||||||
|
|
||||||
void MyMesh::writeOKFrame() {
|
void MyMesh::writeOKFrame() {
|
||||||
uint8_t buf[1];
|
uint8_t buf[1];
|
||||||
buf[0] = RESP_CODE_OK;
|
buf[0] = RESP_CODE_OK;
|
||||||
@@ -276,54 +261,9 @@ bool MyMesh::isAutoAddEnabled() const {
|
|||||||
return (_prefs.manual_add_contacts & 1) == 0;
|
return (_prefs.manual_add_contacts & 1) == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool MyMesh::shouldAutoAddContactType(uint8_t contact_type) const {
|
|
||||||
if ((_prefs.manual_add_contacts & 1) == 0) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint8_t type_bit = 0;
|
|
||||||
switch (contact_type) {
|
|
||||||
case ADV_TYPE_CHAT:
|
|
||||||
type_bit = AUTO_ADD_CHAT;
|
|
||||||
break;
|
|
||||||
case ADV_TYPE_REPEATER:
|
|
||||||
type_bit = AUTO_ADD_REPEATER;
|
|
||||||
break;
|
|
||||||
case ADV_TYPE_ROOM:
|
|
||||||
type_bit = AUTO_ADD_ROOM_SERVER;
|
|
||||||
break;
|
|
||||||
case ADV_TYPE_SENSOR:
|
|
||||||
type_bit = AUTO_ADD_SENSOR;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
return false; // Unknown type, don't auto-add
|
|
||||||
}
|
|
||||||
|
|
||||||
return (_prefs.autoadd_config & type_bit) != 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool MyMesh::shouldOverwriteWhenFull() const {
|
|
||||||
return (_prefs.autoadd_config & AUTO_ADD_OVERWRITE_OLDEST) != 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void MyMesh::onContactOverwrite(const uint8_t* pub_key) {
|
|
||||||
if (_serial->isConnected()) {
|
|
||||||
out_frame[0] = PUSH_CODE_CONTACT_DELETED;
|
|
||||||
memcpy(&out_frame[1], pub_key, PUB_KEY_SIZE);
|
|
||||||
_serial->writeFrame(out_frame, 1 + PUB_KEY_SIZE);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void MyMesh::onContactsFull() {
|
|
||||||
if (_serial->isConnected()) {
|
|
||||||
out_frame[0] = PUSH_CODE_CONTACTS_FULL;
|
|
||||||
_serial->writeFrame(out_frame, 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void MyMesh::onDiscoveredContact(ContactInfo &contact, bool is_new, uint8_t path_len, const uint8_t* path) {
|
void MyMesh::onDiscoveredContact(ContactInfo &contact, bool is_new, uint8_t path_len, const uint8_t* path) {
|
||||||
if (_serial->isConnected()) {
|
if (_serial->isConnected()) {
|
||||||
if (!shouldAutoAddContactType(contact.type) && is_new) {
|
if (!isAutoAddEnabled() && is_new) {
|
||||||
writeContactRespFrame(PUSH_CODE_NEW_ADVERT, contact);
|
writeContactRespFrame(PUSH_CODE_NEW_ADVERT, contact);
|
||||||
} else {
|
} else {
|
||||||
out_frame[0] = PUSH_CODE_ADVERT;
|
out_frame[0] = PUSH_CODE_ADVERT;
|
||||||
@@ -792,7 +732,7 @@ MyMesh::MyMesh(mesh::Radio &radio, mesh::RNG &rng, mesh::RTCClock &rtc, SimpleMe
|
|||||||
|
|
||||||
// defaults
|
// defaults
|
||||||
memset(&_prefs, 0, sizeof(_prefs));
|
memset(&_prefs, 0, sizeof(_prefs));
|
||||||
_prefs.airtime_factor = 1.0; // one half
|
_prefs.airtime_factor = 1.0;
|
||||||
strcpy(_prefs.node_name, "NONAME");
|
strcpy(_prefs.node_name, "NONAME");
|
||||||
_prefs.freq = LORA_FREQ;
|
_prefs.freq = LORA_FREQ;
|
||||||
_prefs.sf = LORA_SF;
|
_prefs.sf = LORA_SF;
|
||||||
@@ -862,7 +802,6 @@ void MyMesh::begin(bool has_display) {
|
|||||||
|
|
||||||
resetContacts();
|
resetContacts();
|
||||||
_store->loadContacts(this);
|
_store->loadContacts(this);
|
||||||
bootstrapRTCfromContacts();
|
|
||||||
addChannel("Public", PUBLIC_GROUP_PSK); // pre-configure Andy's public channel
|
addChannel("Public", PUBLIC_GROUP_PSK); // pre-configure Andy's public channel
|
||||||
_store->loadChannels(this);
|
_store->loadChannels(this);
|
||||||
|
|
||||||
@@ -1347,27 +1286,6 @@ void MyMesh::handleCmdFrame(size_t len) {
|
|||||||
} else {
|
} else {
|
||||||
writeErrFrame(ERR_CODE_NOT_FOUND); // contact not found
|
writeErrFrame(ERR_CODE_NOT_FOUND); // contact not found
|
||||||
}
|
}
|
||||||
} else if (cmd_frame[0] == CMD_SEND_ANON_REQ && len > 1 + PUB_KEY_SIZE) {
|
|
||||||
uint8_t *pub_key = &cmd_frame[1];
|
|
||||||
ContactInfo *recipient = lookupContactByPubKey(pub_key, PUB_KEY_SIZE);
|
|
||||||
uint8_t *data = &cmd_frame[1 + PUB_KEY_SIZE];
|
|
||||||
if (recipient) {
|
|
||||||
uint32_t tag, est_timeout;
|
|
||||||
int result = sendAnonReq(*recipient, data, len - (1 + PUB_KEY_SIZE), tag, est_timeout);
|
|
||||||
if (result == MSG_SEND_FAILED) {
|
|
||||||
writeErrFrame(ERR_CODE_TABLE_FULL);
|
|
||||||
} else {
|
|
||||||
clearPendingReqs();
|
|
||||||
pending_req = tag; // match this to onContactResponse()
|
|
||||||
out_frame[0] = RESP_CODE_SENT;
|
|
||||||
out_frame[1] = (result == MSG_SEND_SENT_FLOOD) ? 1 : 0;
|
|
||||||
memcpy(&out_frame[2], &tag, 4);
|
|
||||||
memcpy(&out_frame[6], &est_timeout, 4);
|
|
||||||
_serial->writeFrame(out_frame, 10);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
writeErrFrame(ERR_CODE_NOT_FOUND); // contact not found
|
|
||||||
}
|
|
||||||
} else if (cmd_frame[0] == CMD_SEND_STATUS_REQ && len >= 1 + PUB_KEY_SIZE) {
|
} else if (cmd_frame[0] == CMD_SEND_STATUS_REQ && len >= 1 + PUB_KEY_SIZE) {
|
||||||
uint8_t *pub_key = &cmd_frame[1];
|
uint8_t *pub_key = &cmd_frame[1];
|
||||||
ContactInfo *recipient = lookupContactByPubKey(pub_key, PUB_KEY_SIZE);
|
ContactInfo *recipient = lookupContactByPubKey(pub_key, PUB_KEY_SIZE);
|
||||||
@@ -1723,15 +1641,6 @@ void MyMesh::handleCmdFrame(size_t len) {
|
|||||||
} else {
|
} else {
|
||||||
writeErrFrame(ERR_CODE_TABLE_FULL);
|
writeErrFrame(ERR_CODE_TABLE_FULL);
|
||||||
}
|
}
|
||||||
} else if (cmd_frame[0] == CMD_SET_AUTOADD_CONFIG) {
|
|
||||||
_prefs.autoadd_config = cmd_frame[1];
|
|
||||||
savePrefs();
|
|
||||||
writeOKFrame();
|
|
||||||
} else if (cmd_frame[0] == CMD_GET_AUTOADD_CONFIG) {
|
|
||||||
int i = 0;
|
|
||||||
out_frame[i++] = RESP_CODE_AUTOADD_CONFIG;
|
|
||||||
out_frame[i++] = _prefs.autoadd_config;
|
|
||||||
_serial->writeFrame(out_frame, i);
|
|
||||||
} else {
|
} else {
|
||||||
writeErrFrame(ERR_CODE_UNSUPPORTED_CMD);
|
writeErrFrame(ERR_CODE_UNSUPPORTED_CMD);
|
||||||
MESH_DEBUG_PRINTLN("ERROR: unknown command: %02X", cmd_frame[0]);
|
MESH_DEBUG_PRINTLN("ERROR: unknown command: %02X", cmd_frame[0]);
|
||||||
|
|||||||
@@ -114,10 +114,6 @@ protected:
|
|||||||
|
|
||||||
void logRxRaw(float snr, float rssi, const uint8_t raw[], int len) override;
|
void logRxRaw(float snr, float rssi, const uint8_t raw[], int len) override;
|
||||||
bool isAutoAddEnabled() const override;
|
bool isAutoAddEnabled() const override;
|
||||||
bool shouldAutoAddContactType(uint8_t type) const override;
|
|
||||||
bool shouldOverwriteWhenFull() const override;
|
|
||||||
void onContactsFull() override;
|
|
||||||
void onContactOverwrite(const uint8_t* pub_key) override;
|
|
||||||
bool onContactPathRecv(ContactInfo& from, uint8_t* in_path, uint8_t in_path_len, uint8_t* out_path, uint8_t out_path_len, uint8_t extra_type, uint8_t* extra, uint8_t extra_len) override;
|
bool onContactPathRecv(ContactInfo& from, uint8_t* in_path, uint8_t in_path_len, uint8_t* out_path, uint8_t out_path_len, uint8_t extra_type, uint8_t* extra, uint8_t extra_len) override;
|
||||||
void onDiscoveredContact(ContactInfo &contact, bool is_new, uint8_t path_len, const uint8_t* path) override;
|
void onDiscoveredContact(ContactInfo &contact, bool is_new, uint8_t path_len, const uint8_t* path) override;
|
||||||
void onContactPathUpdated(const ContactInfo &contact) override;
|
void onContactPathUpdated(const ContactInfo &contact) override;
|
||||||
|
|||||||
@@ -27,5 +27,4 @@ struct NodePrefs { // persisted to file
|
|||||||
uint8_t buzzer_quiet;
|
uint8_t buzzer_quiet;
|
||||||
uint8_t gps_enabled; // GPS enabled flag (0=disabled, 1=enabled)
|
uint8_t gps_enabled; // GPS enabled flag (0=disabled, 1=enabled)
|
||||||
uint32_t gps_interval; // GPS read interval in seconds
|
uint32_t gps_interval; // GPS read interval in seconds
|
||||||
uint8_t autoadd_config; // bitmask for auto-add contacts config
|
|
||||||
};
|
};
|
||||||
@@ -41,21 +41,16 @@
|
|||||||
#define TXT_ACK_DELAY 200
|
#define TXT_ACK_DELAY 200
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define FIRMWARE_VER_LEVEL 2
|
#define FIRMWARE_VER_LEVEL 1
|
||||||
|
|
||||||
#define REQ_TYPE_GET_STATUS 0x01 // same as _GET_STATS
|
#define REQ_TYPE_GET_STATUS 0x01 // same as _GET_STATS
|
||||||
#define REQ_TYPE_KEEP_ALIVE 0x02
|
#define REQ_TYPE_KEEP_ALIVE 0x02
|
||||||
#define REQ_TYPE_GET_TELEMETRY_DATA 0x03
|
#define REQ_TYPE_GET_TELEMETRY_DATA 0x03
|
||||||
#define REQ_TYPE_GET_ACCESS_LIST 0x05
|
#define REQ_TYPE_GET_ACCESS_LIST 0x05
|
||||||
#define REQ_TYPE_GET_NEIGHBOURS 0x06
|
#define REQ_TYPE_GET_NEIGHBOURS 0x06
|
||||||
#define REQ_TYPE_GET_OWNER_INFO 0x07 // FIRMWARE_VER_LEVEL >= 2
|
|
||||||
|
|
||||||
#define RESP_SERVER_LOGIN_OK 0 // response to ANON_REQ
|
#define RESP_SERVER_LOGIN_OK 0 // response to ANON_REQ
|
||||||
|
|
||||||
#define ANON_REQ_TYPE_REGIONS 0x01
|
|
||||||
#define ANON_REQ_TYPE_OWNER 0x02
|
|
||||||
#define ANON_REQ_TYPE_BASIC 0x03 // just remote clock
|
|
||||||
|
|
||||||
#define CLI_REPLY_DELAY_MILLIS 600
|
#define CLI_REPLY_DELAY_MILLIS 600
|
||||||
|
|
||||||
#define LAZY_CONTACTS_WRITE_DELAY 5000
|
#define LAZY_CONTACTS_WRITE_DELAY 5000
|
||||||
@@ -144,64 +139,6 @@ uint8_t MyMesh::handleLoginReq(const mesh::Identity& sender, const uint8_t* secr
|
|||||||
return 13; // reply length
|
return 13; // reply length
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t MyMesh::handleAnonRegionsReq(const mesh::Identity& sender, uint32_t sender_timestamp, const uint8_t* data) {
|
|
||||||
if (anon_limiter.allow(rtc_clock.getCurrentTime())) {
|
|
||||||
// request data has: {reply-path-len}{reply-path}
|
|
||||||
reply_path_len = *data++ & 0x3F;
|
|
||||||
memcpy(reply_path, data, reply_path_len);
|
|
||||||
// data += reply_path_len;
|
|
||||||
|
|
||||||
memcpy(reply_data, &sender_timestamp, 4); // prefix with sender_timestamp, like a tag
|
|
||||||
uint32_t now = getRTCClock()->getCurrentTime();
|
|
||||||
memcpy(&reply_data[4], &now, 4); // include our clock (for easy clock sync, and packet hash uniqueness)
|
|
||||||
|
|
||||||
return 8 + region_map.exportNamesTo((char *) &reply_data[8], sizeof(reply_data) - 12, REGION_DENY_FLOOD); // reply length
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint8_t MyMesh::handleAnonOwnerReq(const mesh::Identity& sender, uint32_t sender_timestamp, const uint8_t* data) {
|
|
||||||
if (anon_limiter.allow(rtc_clock.getCurrentTime())) {
|
|
||||||
// request data has: {reply-path-len}{reply-path}
|
|
||||||
reply_path_len = *data++ & 0x3F;
|
|
||||||
memcpy(reply_path, data, reply_path_len);
|
|
||||||
// data += reply_path_len;
|
|
||||||
|
|
||||||
memcpy(reply_data, &sender_timestamp, 4); // prefix with sender_timestamp, like a tag
|
|
||||||
uint32_t now = getRTCClock()->getCurrentTime();
|
|
||||||
memcpy(&reply_data[4], &now, 4); // include our clock (for easy clock sync, and packet hash uniqueness)
|
|
||||||
sprintf((char *) &reply_data[8], "%s\n%s", _prefs.node_name, _prefs.owner_info);
|
|
||||||
|
|
||||||
return 8 + strlen((char *) &reply_data[8]); // reply length
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint8_t MyMesh::handleAnonClockReq(const mesh::Identity& sender, uint32_t sender_timestamp, const uint8_t* data) {
|
|
||||||
if (anon_limiter.allow(rtc_clock.getCurrentTime())) {
|
|
||||||
// request data has: {reply-path-len}{reply-path}
|
|
||||||
reply_path_len = *data++ & 0x3F;
|
|
||||||
memcpy(reply_path, data, reply_path_len);
|
|
||||||
// data += reply_path_len;
|
|
||||||
|
|
||||||
memcpy(reply_data, &sender_timestamp, 4); // prefix with sender_timestamp, like a tag
|
|
||||||
uint32_t now = getRTCClock()->getCurrentTime();
|
|
||||||
memcpy(&reply_data[4], &now, 4); // include our clock (for easy clock sync, and packet hash uniqueness)
|
|
||||||
reply_data[8] = 0; // features
|
|
||||||
#ifdef WITH_RS232_BRIDGE
|
|
||||||
reply_data[8] |= 0x01; // is bridge, type UART
|
|
||||||
#elif WITH_ESPNOW_BRIDGE
|
|
||||||
reply_data[8] |= 0x03; // is bridge, type ESP-NOW
|
|
||||||
#endif
|
|
||||||
if (_prefs.disable_fwd) { // is this repeater currently disabled
|
|
||||||
reply_data[8] |= 0x80; // is disabled
|
|
||||||
}
|
|
||||||
// TODO: add some kind of moving-window utilisation metric, so can query 'how busy' is this repeater
|
|
||||||
return 9; // reply length
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int MyMesh::handleRequest(ClientInfo *sender, uint32_t sender_timestamp, uint8_t *payload, size_t payload_len) {
|
int MyMesh::handleRequest(ClientInfo *sender, uint32_t sender_timestamp, uint8_t *payload, size_t payload_len) {
|
||||||
// uint32_t now = getRTCClock()->getCurrentTimeUnique();
|
// uint32_t now = getRTCClock()->getCurrentTimeUnique();
|
||||||
// memcpy(reply_data, &now, 4); // response packets always prefixed with timestamp
|
// memcpy(reply_data, &now, 4); // response packets always prefixed with timestamp
|
||||||
@@ -359,9 +296,6 @@ int MyMesh::handleRequest(ClientInfo *sender, uint32_t sender_timestamp, uint8_t
|
|||||||
|
|
||||||
return reply_offset;
|
return reply_offset;
|
||||||
}
|
}
|
||||||
} else if (payload[0] == REQ_TYPE_GET_OWNER_INFO) {
|
|
||||||
sprintf((char *) &reply_data[4], "%s\n%s\n%s", FIRMWARE_VERSION, _prefs.node_name, _prefs.owner_info);
|
|
||||||
return 4 + strlen((char *) &reply_data[4]);
|
|
||||||
}
|
}
|
||||||
return 0; // unknown command
|
return 0; // unknown command
|
||||||
}
|
}
|
||||||
@@ -390,6 +324,14 @@ bool MyMesh::allowPacketForward(const mesh::Packet *packet) {
|
|||||||
MESH_DEBUG_PRINTLN("allowPacketForward: unknown transport code, or wildcard not allowed for FLOOD packet");
|
MESH_DEBUG_PRINTLN("allowPacketForward: unknown transport code, or wildcard not allowed for FLOOD packet");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
// Limit flood advert paket forwarding using a probabilistic reduction defined by P(h) = 0.308^(hops-1)
|
||||||
|
// https://github.com/meshcore-dev/MeshCore/issues/1223
|
||||||
|
double_t roll_dice = (double)rand() / RAND_MAX;
|
||||||
|
double_t forw_prob = pow(0.308, packet->path_len - 1);
|
||||||
|
if (packet->getPayloadType() == PAYLOAD_TYPE_ADVERT && packet->isRouteFlood() && roll_dice > forw_prob)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// all other packets
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -514,18 +456,12 @@ void MyMesh::onAnonDataRecv(mesh::Packet *packet, const uint8_t *secret, const m
|
|||||||
|
|
||||||
data[len] = 0; // ensure null terminator
|
data[len] = 0; // ensure null terminator
|
||||||
uint8_t reply_len;
|
uint8_t reply_len;
|
||||||
|
|
||||||
reply_path_len = -1;
|
|
||||||
if (data[4] == 0 || data[4] >= ' ') { // is password, ie. a login request
|
if (data[4] == 0 || data[4] >= ' ') { // is password, ie. a login request
|
||||||
reply_len = handleLoginReq(sender, secret, timestamp, &data[4], packet->isRouteFlood());
|
reply_len = handleLoginReq(sender, secret, timestamp, &data[4], packet->isRouteFlood());
|
||||||
} else if (data[4] == ANON_REQ_TYPE_REGIONS && packet->isRouteDirect()) {
|
//} else if (data[4] == ANON_REQ_TYPE_*) { // future type codes
|
||||||
reply_len = handleAnonRegionsReq(sender, timestamp, &data[5]);
|
// TODO
|
||||||
} else if (data[4] == ANON_REQ_TYPE_OWNER && packet->isRouteDirect()) {
|
|
||||||
reply_len = handleAnonOwnerReq(sender, timestamp, &data[5]);
|
|
||||||
} else if (data[4] == ANON_REQ_TYPE_BASIC && packet->isRouteDirect()) {
|
|
||||||
reply_len = handleAnonClockReq(sender, timestamp, &data[5]);
|
|
||||||
} else {
|
} else {
|
||||||
reply_len = 0; // unknown/invalid request type
|
reply_len = 0; // unknown request type
|
||||||
}
|
}
|
||||||
|
|
||||||
if (reply_len == 0) return; // invalid request
|
if (reply_len == 0) return; // invalid request
|
||||||
@@ -535,12 +471,9 @@ void MyMesh::onAnonDataRecv(mesh::Packet *packet, const uint8_t *secret, const m
|
|||||||
mesh::Packet* path = createPathReturn(sender, secret, packet->path, packet->path_len,
|
mesh::Packet* path = createPathReturn(sender, secret, packet->path, packet->path_len,
|
||||||
PAYLOAD_TYPE_RESPONSE, reply_data, reply_len);
|
PAYLOAD_TYPE_RESPONSE, reply_data, reply_len);
|
||||||
if (path) sendFlood(path, SERVER_RESPONSE_DELAY);
|
if (path) sendFlood(path, SERVER_RESPONSE_DELAY);
|
||||||
} else if (reply_path_len < 0) {
|
|
||||||
mesh::Packet* reply = createDatagram(PAYLOAD_TYPE_RESPONSE, sender, secret, reply_data, reply_len);
|
|
||||||
if (reply) sendFlood(reply, SERVER_RESPONSE_DELAY);
|
|
||||||
} else {
|
} else {
|
||||||
mesh::Packet* reply = createDatagram(PAYLOAD_TYPE_RESPONSE, sender, secret, reply_data, reply_len);
|
mesh::Packet* reply = createDatagram(PAYLOAD_TYPE_RESPONSE, sender, secret, reply_data, reply_len);
|
||||||
if (reply) sendDirect(reply, reply_path, reply_path_len, SERVER_RESPONSE_DELAY);
|
if (reply) sendFlood(reply, SERVER_RESPONSE_DELAY);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -711,10 +644,14 @@ bool MyMesh::onPeerPathRecv(mesh::Packet *packet, int sender_idx, const uint8_t
|
|||||||
#define CTL_TYPE_NODE_DISCOVER_RESP 0x90
|
#define CTL_TYPE_NODE_DISCOVER_RESP 0x90
|
||||||
|
|
||||||
void MyMesh::onControlDataRecv(mesh::Packet* packet) {
|
void MyMesh::onControlDataRecv(mesh::Packet* packet) {
|
||||||
|
if (!packet->payload) {
|
||||||
|
MESH_DEBUG_PRINTLN("onControlDataRecv: packet->payload is null");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if !defined(STEALTH_MODE)
|
||||||
uint8_t type = packet->payload[0] & 0xF0; // just test upper 4 bits
|
uint8_t type = packet->payload[0] & 0xF0; // just test upper 4 bits
|
||||||
if (type == CTL_TYPE_NODE_DISCOVER_REQ && packet->payload_len >= 6
|
if (type == CTL_TYPE_NODE_DISCOVER_REQ && packet->payload_len >= 6 && discover_limiter.allow(rtc_clock.getCurrentTime())) {
|
||||||
&& !_prefs.disable_fwd && discover_limiter.allow(rtc_clock.getCurrentTime())
|
|
||||||
) {
|
|
||||||
int i = 1;
|
int i = 1;
|
||||||
uint8_t filter = packet->payload[i++];
|
uint8_t filter = packet->payload[i++];
|
||||||
uint32_t tag;
|
uint32_t tag;
|
||||||
@@ -739,14 +676,14 @@ void MyMesh::onControlDataRecv(mesh::Packet* packet) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
MyMesh::MyMesh(mesh::MainBoard &board, mesh::Radio &radio, mesh::MillisecondClock &ms, mesh::RNG &rng,
|
MyMesh::MyMesh(mesh::MainBoard &board, mesh::Radio &radio, mesh::MillisecondClock &ms, mesh::RNG &rng,
|
||||||
mesh::RTCClock &rtc, mesh::MeshTables &tables)
|
mesh::RTCClock &rtc, mesh::MeshTables &tables)
|
||||||
: mesh::Mesh(radio, ms, rng, rtc, *new StaticPoolPacketManager(32), tables),
|
: mesh::Mesh(radio, ms, rng, rtc, *new StaticPoolPacketManager(32), tables),
|
||||||
_cli(board, rtc, sensors, &_prefs, this), telemetry(MAX_PACKET_PAYLOAD - 4), region_map(key_store), temp_map(key_store),
|
_cli(board, rtc, sensors, &_prefs, this), telemetry(MAX_PACKET_PAYLOAD - 4), region_map(key_store), temp_map(key_store),
|
||||||
discover_limiter(4, 120), // max 4 every 2 minutes
|
discover_limiter(4, 120) // max 4 every 2 minutes
|
||||||
anon_limiter(4, 180) // max 4 every 3 minutes
|
|
||||||
#if defined(WITH_RS232_BRIDGE)
|
#if defined(WITH_RS232_BRIDGE)
|
||||||
, bridge(&_prefs, WITH_RS232_BRIDGE, _mgr, &rtc)
|
, bridge(&_prefs, WITH_RS232_BRIDGE, _mgr, &rtc)
|
||||||
#endif
|
#endif
|
||||||
@@ -768,7 +705,7 @@ MyMesh::MyMesh(mesh::MainBoard &board, mesh::Radio &radio, mesh::MillisecondCloc
|
|||||||
|
|
||||||
// defaults
|
// defaults
|
||||||
memset(&_prefs, 0, sizeof(_prefs));
|
memset(&_prefs, 0, sizeof(_prefs));
|
||||||
_prefs.airtime_factor = 1.0; // one half
|
_prefs.airtime_factor = 1.0;
|
||||||
_prefs.rx_delay_base = 0.0f; // turn off by default, was 10.0;
|
_prefs.rx_delay_base = 0.0f; // turn off by default, was 10.0;
|
||||||
_prefs.tx_delay_factor = 0.5f; // was 0.25f
|
_prefs.tx_delay_factor = 0.5f; // was 0.25f
|
||||||
_prefs.direct_tx_delay_factor = 0.2f; // was zero
|
_prefs.direct_tx_delay_factor = 0.2f; // was zero
|
||||||
@@ -781,8 +718,8 @@ MyMesh::MyMesh(mesh::MainBoard &board, mesh::Radio &radio, mesh::MillisecondCloc
|
|||||||
_prefs.bw = LORA_BW;
|
_prefs.bw = LORA_BW;
|
||||||
_prefs.cr = LORA_CR;
|
_prefs.cr = LORA_CR;
|
||||||
_prefs.tx_power_dbm = LORA_TX_POWER;
|
_prefs.tx_power_dbm = LORA_TX_POWER;
|
||||||
_prefs.advert_interval = 1; // default to 2 minutes for NEW installs
|
_prefs.advert_interval = DEF_LOCAL_ADVERT_INTERVAL;
|
||||||
_prefs.flood_advert_interval = 12; // 12 hours
|
_prefs.flood_advert_interval = DEF_FLOOD_ADVERT_INTERVAL;
|
||||||
_prefs.flood_max = 64;
|
_prefs.flood_max = 64;
|
||||||
_prefs.interference_threshold = 0; // disabled
|
_prefs.interference_threshold = 0; // disabled
|
||||||
|
|
||||||
@@ -854,10 +791,14 @@ bool MyMesh::formatFileSystem() {
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void MyMesh::sendSelfAdvertisement(int delay_millis) {
|
void MyMesh::sendSelfAdvertisement(int delay_millis, bool flood) {
|
||||||
mesh::Packet *pkt = createSelfAdvert();
|
mesh::Packet *pkt = createSelfAdvert();
|
||||||
if (pkt) {
|
if (pkt) {
|
||||||
sendFlood(pkt, delay_millis);
|
if (flood) {
|
||||||
|
sendFlood(pkt, delay_millis);
|
||||||
|
} else {
|
||||||
|
sendZeroHop(pkt, delay_millis);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
MESH_DEBUG_PRINTLN("ERROR: unable to create advertisement packet!");
|
MESH_DEBUG_PRINTLN("ERROR: unable to create advertisement packet!");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -88,14 +88,12 @@ class MyMesh : public mesh::Mesh, public CommonCLICallbacks {
|
|||||||
NodePrefs _prefs;
|
NodePrefs _prefs;
|
||||||
CommonCLI _cli;
|
CommonCLI _cli;
|
||||||
uint8_t reply_data[MAX_PACKET_PAYLOAD];
|
uint8_t reply_data[MAX_PACKET_PAYLOAD];
|
||||||
uint8_t reply_path[MAX_PATH_SIZE];
|
|
||||||
int8_t reply_path_len;
|
|
||||||
ClientACL acl;
|
ClientACL acl;
|
||||||
TransportKeyStore key_store;
|
TransportKeyStore key_store;
|
||||||
RegionMap region_map, temp_map;
|
RegionMap region_map, temp_map;
|
||||||
RegionEntry* load_stack[8];
|
RegionEntry* load_stack[8];
|
||||||
RegionEntry* recv_pkt_region;
|
RegionEntry* recv_pkt_region;
|
||||||
RateLimiter discover_limiter, anon_limiter;
|
RateLimiter discover_limiter;
|
||||||
bool region_load_active;
|
bool region_load_active;
|
||||||
unsigned long dirty_contacts_expiry;
|
unsigned long dirty_contacts_expiry;
|
||||||
#if MAX_NEIGHBOURS
|
#if MAX_NEIGHBOURS
|
||||||
@@ -116,9 +114,6 @@ class MyMesh : public mesh::Mesh, public CommonCLICallbacks {
|
|||||||
|
|
||||||
void putNeighbour(const mesh::Identity& id, uint32_t timestamp, float snr);
|
void putNeighbour(const mesh::Identity& id, uint32_t timestamp, float snr);
|
||||||
uint8_t handleLoginReq(const mesh::Identity& sender, const uint8_t* secret, uint32_t sender_timestamp, const uint8_t* data, bool is_flood);
|
uint8_t handleLoginReq(const mesh::Identity& sender, const uint8_t* secret, uint32_t sender_timestamp, const uint8_t* data, bool is_flood);
|
||||||
uint8_t handleAnonRegionsReq(const mesh::Identity& sender, uint32_t sender_timestamp, const uint8_t* data);
|
|
||||||
uint8_t handleAnonOwnerReq(const mesh::Identity& sender, uint32_t sender_timestamp, const uint8_t* data);
|
|
||||||
uint8_t handleAnonClockReq(const mesh::Identity& sender, uint32_t sender_timestamp, const uint8_t* data);
|
|
||||||
int handleRequest(ClientInfo* sender, uint32_t sender_timestamp, uint8_t* payload, size_t payload_len);
|
int handleRequest(ClientInfo* sender, uint32_t sender_timestamp, uint8_t* payload, size_t payload_len);
|
||||||
mesh::Packet* createSelfAdvert();
|
mesh::Packet* createSelfAdvert();
|
||||||
|
|
||||||
@@ -186,7 +181,7 @@ public:
|
|||||||
|
|
||||||
void applyTempRadioParams(float freq, float bw, uint8_t sf, uint8_t cr, int timeout_mins) override;
|
void applyTempRadioParams(float freq, float bw, uint8_t sf, uint8_t cr, int timeout_mins) override;
|
||||||
bool formatFileSystem() override;
|
bool formatFileSystem() override;
|
||||||
void sendSelfAdvertisement(int delay_millis) override;
|
void sendSelfAdvertisement(int delay_millis, bool flood = true) override;
|
||||||
void updateAdvertTimer() override;
|
void updateAdvertTimer() override;
|
||||||
void updateFloodAdvertTimer() override;
|
void updateFloodAdvertTimer() override;
|
||||||
|
|
||||||
|
|||||||
@@ -87,8 +87,10 @@ void setup() {
|
|||||||
ui_task.begin(the_mesh.getNodePrefs(), FIRMWARE_BUILD_DATE, FIRMWARE_VERSION);
|
ui_task.begin(the_mesh.getNodePrefs(), FIRMWARE_BUILD_DATE, FIRMWARE_VERSION);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// send out initial Advertisement to the mesh
|
#if !defined(STEALTH_MODE) && !defined(NO_BOOT_ADVERT)
|
||||||
the_mesh.sendSelfAdvertisement(16000);
|
// send out initial Zero Hop Advertisement to the mesh
|
||||||
|
the_mesh.sendSelfAdvertisement(16000, false);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void loop() {
|
void loop() {
|
||||||
|
|||||||
@@ -275,6 +275,15 @@ uint32_t MyMesh::getDirectRetransmitDelay(const mesh::Packet *packet) {
|
|||||||
bool MyMesh::allowPacketForward(const mesh::Packet *packet) {
|
bool MyMesh::allowPacketForward(const mesh::Packet *packet) {
|
||||||
if (_prefs.disable_fwd) return false;
|
if (_prefs.disable_fwd) return false;
|
||||||
if (packet->isRouteFlood() && packet->path_len >= _prefs.flood_max) return false;
|
if (packet->isRouteFlood() && packet->path_len >= _prefs.flood_max) return false;
|
||||||
|
|
||||||
|
// Limit flood advert paket forwarding using a probabilistic reduction defined by P(h) = 0.308^(hops-1)
|
||||||
|
// https://github.com/meshcore-dev/MeshCore/issues/1223
|
||||||
|
double_t roll_dice = (double)rand() / RAND_MAX;
|
||||||
|
double_t forw_prob = pow(0.308, packet->path_len - 1);
|
||||||
|
if (packet->getPayloadType() == PAYLOAD_TYPE_ADVERT && packet->isRouteFlood() && roll_dice > forw_prob)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// all other packets
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -597,7 +606,7 @@ MyMesh::MyMesh(mesh::MainBoard &board, mesh::Radio &radio, mesh::MillisecondCloc
|
|||||||
|
|
||||||
// defaults
|
// defaults
|
||||||
memset(&_prefs, 0, sizeof(_prefs));
|
memset(&_prefs, 0, sizeof(_prefs));
|
||||||
_prefs.airtime_factor = 1.0; // one half
|
_prefs.airtime_factor = 1.0;
|
||||||
_prefs.rx_delay_base = 0.0f; // off by default, was 10.0
|
_prefs.rx_delay_base = 0.0f; // off by default, was 10.0
|
||||||
_prefs.tx_delay_factor = 0.5f; // was 0.25f;
|
_prefs.tx_delay_factor = 0.5f; // was 0.25f;
|
||||||
_prefs.direct_tx_delay_factor = 0.2f; // was zero
|
_prefs.direct_tx_delay_factor = 0.2f; // was zero
|
||||||
@@ -611,8 +620,8 @@ MyMesh::MyMesh(mesh::MainBoard &board, mesh::Radio &radio, mesh::MillisecondCloc
|
|||||||
_prefs.cr = LORA_CR;
|
_prefs.cr = LORA_CR;
|
||||||
_prefs.tx_power_dbm = LORA_TX_POWER;
|
_prefs.tx_power_dbm = LORA_TX_POWER;
|
||||||
_prefs.disable_fwd = 1;
|
_prefs.disable_fwd = 1;
|
||||||
_prefs.advert_interval = 1; // default to 2 minutes for NEW installs
|
_prefs.advert_interval = DEF_LOCAL_ADVERT_INTERVAL;
|
||||||
_prefs.flood_advert_interval = 12; // 12 hours
|
_prefs.flood_advert_interval = DEF_FLOOD_ADVERT_INTERVAL;
|
||||||
_prefs.flood_max = 64;
|
_prefs.flood_max = 64;
|
||||||
_prefs.interference_threshold = 0; // disabled
|
_prefs.interference_threshold = 0; // disabled
|
||||||
#ifdef ROOM_PASSWORD
|
#ifdef ROOM_PASSWORD
|
||||||
@@ -675,10 +684,14 @@ bool MyMesh::formatFileSystem() {
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void MyMesh::sendSelfAdvertisement(int delay_millis) {
|
void MyMesh::sendSelfAdvertisement(int delay_millis, bool flood) {
|
||||||
mesh::Packet *pkt = createSelfAdvert();
|
mesh::Packet *pkt = createSelfAdvert();
|
||||||
if (pkt) {
|
if (pkt) {
|
||||||
sendFlood(pkt, delay_millis);
|
if (flood) {
|
||||||
|
sendFlood(pkt, delay_millis);
|
||||||
|
} else {
|
||||||
|
sendZeroHop(pkt, delay_millis);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
MESH_DEBUG_PRINTLN("ERROR: unable to create advertisement packet!");
|
MESH_DEBUG_PRINTLN("ERROR: unable to create advertisement packet!");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -177,7 +177,7 @@ public:
|
|||||||
|
|
||||||
void applyTempRadioParams(float freq, float bw, uint8_t sf, uint8_t cr, int timeout_mins) override;
|
void applyTempRadioParams(float freq, float bw, uint8_t sf, uint8_t cr, int timeout_mins) override;
|
||||||
bool formatFileSystem() override;
|
bool formatFileSystem() override;
|
||||||
void sendSelfAdvertisement(int delay_millis) override;
|
void sendSelfAdvertisement(int delay_millis, bool flood = true) override;
|
||||||
void updateAdvertTimer() override;
|
void updateAdvertTimer() override;
|
||||||
void updateFloodAdvertTimer() override;
|
void updateFloodAdvertTimer() override;
|
||||||
|
|
||||||
|
|||||||
@@ -76,8 +76,10 @@ void setup() {
|
|||||||
ui_task.begin(the_mesh.getNodePrefs(), FIRMWARE_BUILD_DATE, FIRMWARE_VERSION);
|
ui_task.begin(the_mesh.getNodePrefs(), FIRMWARE_BUILD_DATE, FIRMWARE_VERSION);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// send out initial Advertisement to the mesh
|
#if !defined(STEALTH_MODE) && !defined(NO_BOOT_ADVERT)
|
||||||
the_mesh.sendSelfAdvertisement(16000);
|
// send out initial Zero Hop Advertisement to the mesh
|
||||||
|
the_mesh.sendSelfAdvertisement(16000, false);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void loop() {
|
void loop() {
|
||||||
|
|||||||
@@ -280,7 +280,7 @@ public:
|
|||||||
{
|
{
|
||||||
// defaults
|
// defaults
|
||||||
memset(&_prefs, 0, sizeof(_prefs));
|
memset(&_prefs, 0, sizeof(_prefs));
|
||||||
_prefs.airtime_factor = 2.0; // one third
|
_prefs.airtime_factor = 1.0;
|
||||||
strcpy(_prefs.node_name, "NONAME");
|
strcpy(_prefs.node_name, "NONAME");
|
||||||
_prefs.freq = LORA_FREQ;
|
_prefs.freq = LORA_FREQ;
|
||||||
_prefs.tx_power_dbm = LORA_TX_POWER;
|
_prefs.tx_power_dbm = LORA_TX_POWER;
|
||||||
|
|||||||
@@ -705,7 +705,7 @@ SensorMesh::SensorMesh(mesh::MainBoard& board, mesh::Radio& radio, mesh::Millise
|
|||||||
|
|
||||||
// defaults
|
// defaults
|
||||||
memset(&_prefs, 0, sizeof(_prefs));
|
memset(&_prefs, 0, sizeof(_prefs));
|
||||||
_prefs.airtime_factor = 1.0; // one half
|
_prefs.airtime_factor = 1.0;
|
||||||
_prefs.rx_delay_base = 0.0f; // turn off by default, was 10.0;
|
_prefs.rx_delay_base = 0.0f; // turn off by default, was 10.0;
|
||||||
_prefs.tx_delay_factor = 0.5f; // was 0.25f
|
_prefs.tx_delay_factor = 0.5f; // was 0.25f
|
||||||
_prefs.direct_tx_delay_factor = 0.2f; // was zero
|
_prefs.direct_tx_delay_factor = 0.2f; // was zero
|
||||||
@@ -718,7 +718,7 @@ SensorMesh::SensorMesh(mesh::MainBoard& board, mesh::Radio& radio, mesh::Millise
|
|||||||
_prefs.bw = LORA_BW;
|
_prefs.bw = LORA_BW;
|
||||||
_prefs.cr = LORA_CR;
|
_prefs.cr = LORA_CR;
|
||||||
_prefs.tx_power_dbm = LORA_TX_POWER;
|
_prefs.tx_power_dbm = LORA_TX_POWER;
|
||||||
_prefs.advert_interval = 1; // default to 2 minutes for NEW installs
|
_prefs.advert_interval = DEF_LOCAL_ADVERT_INTERVAL;
|
||||||
_prefs.flood_advert_interval = 0; // disabled
|
_prefs.flood_advert_interval = 0; // disabled
|
||||||
_prefs.disable_fwd = true;
|
_prefs.disable_fwd = true;
|
||||||
_prefs.flood_max = 64;
|
_prefs.flood_max = 64;
|
||||||
@@ -788,10 +788,14 @@ void SensorMesh::applyTempRadioParams(float freq, float bw, uint8_t sf, uint8_t
|
|||||||
revert_radio_at = futureMillis(2000 + timeout_mins*60*1000); // schedule when to revert radio params
|
revert_radio_at = futureMillis(2000 + timeout_mins*60*1000); // schedule when to revert radio params
|
||||||
}
|
}
|
||||||
|
|
||||||
void SensorMesh::sendSelfAdvertisement(int delay_millis) {
|
void SensorMesh::sendSelfAdvertisement(int delay_millis, bool flood) {
|
||||||
mesh::Packet* pkt = createSelfAdvert();
|
mesh::Packet* pkt = createSelfAdvert();
|
||||||
if (pkt) {
|
if (pkt) {
|
||||||
sendFlood(pkt, delay_millis);
|
if (flood) {
|
||||||
|
sendFlood(pkt, delay_millis);
|
||||||
|
} else {
|
||||||
|
sendZeroHop(pkt, delay_millis);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
MESH_DEBUG_PRINTLN("ERROR: unable to create advertisement packet!");
|
MESH_DEBUG_PRINTLN("ERROR: unable to create advertisement packet!");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -60,7 +60,7 @@ public:
|
|||||||
NodePrefs* getNodePrefs() { return &_prefs; }
|
NodePrefs* getNodePrefs() { return &_prefs; }
|
||||||
void savePrefs() override { _cli.savePrefs(_fs); }
|
void savePrefs() override { _cli.savePrefs(_fs); }
|
||||||
bool formatFileSystem() override;
|
bool formatFileSystem() override;
|
||||||
void sendSelfAdvertisement(int delay_millis) override;
|
void sendSelfAdvertisement(int delay_millis, bool flood = true) override;
|
||||||
void updateAdvertTimer() override;
|
void updateAdvertTimer() override;
|
||||||
void updateFloodAdvertTimer() override;
|
void updateFloodAdvertTimer() override;
|
||||||
void setLoggingOn(bool enable) override { }
|
void setLoggingOn(bool enable) override { }
|
||||||
|
|||||||
@@ -110,8 +110,10 @@ void setup() {
|
|||||||
ui_task.begin(the_mesh.getNodePrefs(), FIRMWARE_BUILD_DATE, FIRMWARE_VERSION);
|
ui_task.begin(the_mesh.getNodePrefs(), FIRMWARE_BUILD_DATE, FIRMWARE_VERSION);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// send out initial Advertisement to the mesh
|
#if !defined(STEALTH_MODE) && !defined(NO_BOOT_ADVERT)
|
||||||
the_mesh.sendSelfAdvertisement(16000);
|
// send out initial Zero Hop Advertisement to the mesh
|
||||||
|
the_mesh.sendSelfAdvertisement(16000, false);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void loop() {
|
void loop() {
|
||||||
|
|||||||
@@ -23,12 +23,17 @@ lib_deps =
|
|||||||
adafruit/RTClib @ ^2.1.3
|
adafruit/RTClib @ ^2.1.3
|
||||||
melopero/Melopero RV3028 @ ^1.1.0
|
melopero/Melopero RV3028 @ ^1.1.0
|
||||||
electroniccats/CayenneLPP @ 1.6.1
|
electroniccats/CayenneLPP @ 1.6.1
|
||||||
build_flags = -w -DNDEBUG -DRADIOLIB_STATIC_ONLY=1 -DRADIOLIB_GODMODE=1
|
build_flags = -w -DNDEBUG
|
||||||
-D LORA_FREQ=869.525
|
-D LORA_FREQ=869.618
|
||||||
-D LORA_BW=250
|
-D LORA_BW=62.5
|
||||||
-D LORA_SF=11
|
-D LORA_SF=8
|
||||||
|
-D LORA_CR=8
|
||||||
|
;
|
||||||
-D ENABLE_PRIVATE_KEY_IMPORT=1 ; NOTE: comment these out for more secure firmware
|
-D ENABLE_PRIVATE_KEY_IMPORT=1 ; NOTE: comment these out for more secure firmware
|
||||||
-D ENABLE_PRIVATE_KEY_EXPORT=1
|
-D ENABLE_PRIVATE_KEY_EXPORT=1
|
||||||
|
;
|
||||||
|
-D RADIOLIB_STATIC_ONLY=1
|
||||||
|
-D RADIOLIB_GODMODE=1
|
||||||
-D RADIOLIB_EXCLUDE_CC1101=1
|
-D RADIOLIB_EXCLUDE_CC1101=1
|
||||||
-D RADIOLIB_EXCLUDE_RF69=1
|
-D RADIOLIB_EXCLUDE_RF69=1
|
||||||
-D RADIOLIB_EXCLUDE_SX1231=1
|
-D RADIOLIB_EXCLUDE_SX1231=1
|
||||||
@@ -43,6 +48,15 @@ build_flags = -w -DNDEBUG -DRADIOLIB_STATIC_ONLY=1 -DRADIOLIB_GODMODE=1
|
|||||||
-D RADIOLIB_EXCLUDE_BELL=1
|
-D RADIOLIB_EXCLUDE_BELL=1
|
||||||
-D RADIOLIB_EXCLUDE_RTTY=1
|
-D RADIOLIB_EXCLUDE_RTTY=1
|
||||||
-D RADIOLIB_EXCLUDE_SSTV=1
|
-D RADIOLIB_EXCLUDE_SSTV=1
|
||||||
|
;
|
||||||
|
-D MIN_LOCAL_ADVERT_INTERVAL=60
|
||||||
|
-D MAX_LOCAL_ADVERT_INTERVAL=10080 ;1 week
|
||||||
|
-D DEF_LOCAL_ADVERT_INTERVAL=2 ; default to 2 minutes for NEW installs
|
||||||
|
-D MIN_FLOOD_ADVERT_INTERVAL=48
|
||||||
|
-D MAX_FLOOD_ADVERT_INTERVAL=672 ; 4 weeks
|
||||||
|
-D DEF_FLOOD_ADVERT_INTERVAL=48 ; default to 12 hours for NEW installs
|
||||||
|
; -D NO_BOOT_ADVERT=1 ; disable boot advertisement
|
||||||
|
; -D STEALTH_MODE=1 ; disable all advertisements and DISCOVER_REQ
|
||||||
build_src_filter =
|
build_src_filter =
|
||||||
+<*.cpp>
|
+<*.cpp>
|
||||||
+<helpers/*.cpp>
|
+<helpers/*.cpp>
|
||||||
|
|||||||
@@ -20,12 +20,34 @@ void Dispatcher::begin() {
|
|||||||
_err_flags = 0;
|
_err_flags = 0;
|
||||||
radio_nonrx_start = _ms->getMillis();
|
radio_nonrx_start = _ms->getMillis();
|
||||||
|
|
||||||
|
duty_cycle_window_ms = getDutyCycleWindowMs();
|
||||||
|
float duty_cycle = 1.0f / (1.0f + getAirtimeBudgetFactor());
|
||||||
|
tx_budget_ms = (unsigned long)(duty_cycle_window_ms * duty_cycle);
|
||||||
|
last_budget_update = _ms->getMillis();
|
||||||
|
|
||||||
_radio->begin();
|
_radio->begin();
|
||||||
prev_isrecv_mode = _radio->isInRecvMode();
|
prev_isrecv_mode = _radio->isInRecvMode();
|
||||||
}
|
}
|
||||||
|
|
||||||
float Dispatcher::getAirtimeBudgetFactor() const {
|
float Dispatcher::getAirtimeBudgetFactor() const {
|
||||||
return 2.0; // default, 33.3% (1/3rd)
|
return 1.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Dispatcher::updateTxBudget() {
|
||||||
|
unsigned long now = _ms->getMillis();
|
||||||
|
unsigned long elapsed = now - last_budget_update;
|
||||||
|
|
||||||
|
float duty_cycle = 1.0f / (1.0f + getAirtimeBudgetFactor());
|
||||||
|
unsigned long max_budget = (unsigned long)(getDutyCycleWindowMs() * duty_cycle);
|
||||||
|
|
||||||
|
unsigned long refill = (unsigned long)(elapsed * duty_cycle);
|
||||||
|
tx_budget_ms += refill;
|
||||||
|
|
||||||
|
if (tx_budget_ms > max_budget) {
|
||||||
|
tx_budget_ms = max_budget;
|
||||||
|
}
|
||||||
|
|
||||||
|
last_budget_update = now;
|
||||||
}
|
}
|
||||||
|
|
||||||
int Dispatcher::calcRxDelay(float score, uint32_t air_time) const {
|
int Dispatcher::calcRxDelay(float score, uint32_t air_time) const {
|
||||||
@@ -61,11 +83,24 @@ void Dispatcher::loop() {
|
|||||||
if (outbound) { // waiting for outbound send to be completed
|
if (outbound) { // waiting for outbound send to be completed
|
||||||
if (_radio->isSendComplete()) {
|
if (_radio->isSendComplete()) {
|
||||||
long t = _ms->getMillis() - outbound_start;
|
long t = _ms->getMillis() - outbound_start;
|
||||||
total_air_time += t; // keep track of how much air time we are using
|
total_air_time += t;
|
||||||
//Serial.print(" airtime="); Serial.println(t);
|
//Serial.print(" airtime="); Serial.println(t);
|
||||||
|
|
||||||
// will need radio silence up to next_tx_time
|
updateTxBudget();
|
||||||
next_tx_time = futureMillis(t * getAirtimeBudgetFactor());
|
|
||||||
|
if (t > tx_budget_ms) {
|
||||||
|
tx_budget_ms = 0;
|
||||||
|
} else {
|
||||||
|
tx_budget_ms -= t;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (tx_budget_ms < 100) {
|
||||||
|
float duty_cycle = 1.0f / (1.0f + getAirtimeBudgetFactor());
|
||||||
|
unsigned long needed = 100 - tx_budget_ms;
|
||||||
|
next_tx_time = futureMillis((unsigned long)(needed / duty_cycle));
|
||||||
|
} else {
|
||||||
|
next_tx_time = _ms->getMillis();
|
||||||
|
}
|
||||||
|
|
||||||
_radio->onSendFinished();
|
_radio->onSendFinished();
|
||||||
logTx(outbound, 2 + outbound->path_len + outbound->payload_len);
|
logTx(outbound, 2 + outbound->path_len + outbound->payload_len);
|
||||||
@@ -224,9 +259,20 @@ void Dispatcher::processRecvPacket(Packet* pkt) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void Dispatcher::checkSend() {
|
void Dispatcher::checkSend() {
|
||||||
if (_mgr->getOutboundCount(_ms->getMillis()) == 0) return; // nothing waiting to send
|
if (_mgr->getOutboundCount(_ms->getMillis()) == 0) return;
|
||||||
if (!millisHasNowPassed(next_tx_time)) return; // still in 'radio silence' phase (from airtime budget setting)
|
|
||||||
if (_radio->isReceiving()) { // LBT - check if radio is currently mid-receive, or if channel activity
|
updateTxBudget();
|
||||||
|
|
||||||
|
uint32_t est_airtime = _radio->getEstAirtimeFor(MAX_TRANS_UNIT);
|
||||||
|
if (tx_budget_ms < est_airtime / 2) {
|
||||||
|
float duty_cycle = 1.0f / (1.0f + getAirtimeBudgetFactor());
|
||||||
|
unsigned long needed = est_airtime / 2 - tx_budget_ms;
|
||||||
|
next_tx_time = futureMillis((unsigned long)(needed / duty_cycle));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!millisHasNowPassed(next_tx_time)) return;
|
||||||
|
if (_radio->isReceiving()) {
|
||||||
if (cad_busy_start == 0) {
|
if (cad_busy_start == 0) {
|
||||||
cad_busy_start = _ms->getMillis(); // record when CAD busy state started
|
cad_busy_start = _ms->getMillis(); // record when CAD busy state started
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -122,8 +122,12 @@ class Dispatcher {
|
|||||||
bool prev_isrecv_mode;
|
bool prev_isrecv_mode;
|
||||||
uint32_t n_sent_flood, n_sent_direct;
|
uint32_t n_sent_flood, n_sent_direct;
|
||||||
uint32_t n_recv_flood, n_recv_direct;
|
uint32_t n_recv_flood, n_recv_direct;
|
||||||
|
unsigned long tx_budget_ms;
|
||||||
|
unsigned long last_budget_update;
|
||||||
|
unsigned long duty_cycle_window_ms;
|
||||||
|
|
||||||
void processRecvPacket(Packet* pkt);
|
void processRecvPacket(Packet* pkt);
|
||||||
|
void updateTxBudget();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
PacketManager* _mgr;
|
PacketManager* _mgr;
|
||||||
@@ -142,6 +146,9 @@ protected:
|
|||||||
_err_flags = 0;
|
_err_flags = 0;
|
||||||
radio_nonrx_start = 0;
|
radio_nonrx_start = 0;
|
||||||
prev_isrecv_mode = true;
|
prev_isrecv_mode = true;
|
||||||
|
tx_budget_ms = 0;
|
||||||
|
last_budget_update = 0;
|
||||||
|
duty_cycle_window_ms = 3600000;
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual DispatcherAction onRecvPacket(Packet* pkt) = 0;
|
virtual DispatcherAction onRecvPacket(Packet* pkt) = 0;
|
||||||
@@ -159,6 +166,7 @@ protected:
|
|||||||
virtual uint32_t getCADFailMaxDuration() const;
|
virtual uint32_t getCADFailMaxDuration() const;
|
||||||
virtual int getInterferenceThreshold() const { return 0; } // disabled by default
|
virtual int getInterferenceThreshold() const { return 0; } // disabled by default
|
||||||
virtual int getAGCResetInterval() const { return 0; } // disabled by default
|
virtual int getAGCResetInterval() const { return 0; } // disabled by default
|
||||||
|
virtual unsigned long getDutyCycleWindowMs() const { return 3600000; }
|
||||||
|
|
||||||
public:
|
public:
|
||||||
void begin();
|
void begin();
|
||||||
@@ -168,8 +176,9 @@ public:
|
|||||||
void releasePacket(Packet* packet);
|
void releasePacket(Packet* packet);
|
||||||
void sendPacket(Packet* packet, uint8_t priority, uint32_t delay_millis=0);
|
void sendPacket(Packet* packet, uint8_t priority, uint32_t delay_millis=0);
|
||||||
|
|
||||||
unsigned long getTotalAirTime() const { return total_air_time; } // in milliseconds
|
unsigned long getTotalAirTime() const { return total_air_time; }
|
||||||
unsigned long getReceiveAirTime() const {return rx_air_time; }
|
unsigned long getReceiveAirTime() const {return rx_air_time; }
|
||||||
|
unsigned long getRemainingTxBudget() const { return tx_budget_ms; }
|
||||||
uint32_t getNumSentFlood() const { return n_sent_flood; }
|
uint32_t getNumSentFlood() const { return n_sent_flood; }
|
||||||
uint32_t getNumSentDirect() const { return n_sent_direct; }
|
uint32_t getNumSentDirect() const { return n_sent_direct; }
|
||||||
uint32_t getNumRecvFlood() const { return n_recv_flood; }
|
uint32_t getNumRecvFlood() const { return n_recv_flood; }
|
||||||
|
|||||||
@@ -55,54 +55,6 @@ void BaseChatMesh::sendAckTo(const ContactInfo& dest, uint32_t ack_hash) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void BaseChatMesh::bootstrapRTCfromContacts() {
|
|
||||||
uint32_t latest = 0;
|
|
||||||
for (int i = 0; i < num_contacts; i++) {
|
|
||||||
if (contacts[i].lastmod > latest) {
|
|
||||||
latest = contacts[i].lastmod;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (latest != 0) {
|
|
||||||
getRTCClock()->setCurrentTime(latest + 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ContactInfo* BaseChatMesh::allocateContactSlot() {
|
|
||||||
if (num_contacts < MAX_CONTACTS) {
|
|
||||||
return &contacts[num_contacts++];
|
|
||||||
} else if (shouldOverwriteWhenFull()) {
|
|
||||||
// Find oldest non-favourite contact by oldest lastmod timestamp
|
|
||||||
int oldest_idx = -1;
|
|
||||||
uint32_t oldest_lastmod = 0xFFFFFFFF;
|
|
||||||
for (int i = 0; i < num_contacts; i++) {
|
|
||||||
bool is_favourite = (contacts[i].flags & 0x01) != 0;
|
|
||||||
if (!is_favourite && contacts[i].lastmod < oldest_lastmod) {
|
|
||||||
oldest_lastmod = contacts[i].lastmod;
|
|
||||||
oldest_idx = i;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (oldest_idx >= 0) {
|
|
||||||
onContactOverwrite(contacts[oldest_idx].id.pub_key);
|
|
||||||
return &contacts[oldest_idx];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return NULL; // no space, no overwrite or all contacts are all favourites
|
|
||||||
}
|
|
||||||
|
|
||||||
void BaseChatMesh::populateContactFromAdvert(ContactInfo& ci, const mesh::Identity& id, const AdvertDataParser& parser, uint32_t timestamp) {
|
|
||||||
memset(&ci, 0, sizeof(ci));
|
|
||||||
ci.id = id;
|
|
||||||
ci.out_path_len = -1; // initially out_path is unknown
|
|
||||||
StrHelper::strncpy(ci.name, parser.getName(), sizeof(ci.name));
|
|
||||||
ci.type = parser.getType();
|
|
||||||
if (parser.hasLatLon()) {
|
|
||||||
ci.gps_lat = parser.getIntLat();
|
|
||||||
ci.gps_lon = parser.getIntLon();
|
|
||||||
}
|
|
||||||
ci.last_advert_timestamp = timestamp;
|
|
||||||
ci.lastmod = getRTCClock()->getCurrentTime();
|
|
||||||
}
|
|
||||||
|
|
||||||
void BaseChatMesh::onAdvertRecv(mesh::Packet* packet, const mesh::Identity& id, uint32_t timestamp, const uint8_t* app_data, size_t app_data_len) {
|
void BaseChatMesh::onAdvertRecv(mesh::Packet* packet, const mesh::Identity& id, uint32_t timestamp, const uint8_t* app_data, size_t app_data_len) {
|
||||||
AdvertDataParser parser(app_data, app_data_len);
|
AdvertDataParser parser(app_data, app_data_len);
|
||||||
if (!(parser.isValid() && parser.hasName())) {
|
if (!(parser.isValid() && parser.hasName())) {
|
||||||
@@ -135,37 +87,48 @@ void BaseChatMesh::onAdvertRecv(mesh::Packet* packet, const mesh::Identity& id,
|
|||||||
|
|
||||||
bool is_new = false;
|
bool is_new = false;
|
||||||
if (from == NULL) {
|
if (from == NULL) {
|
||||||
if (!shouldAutoAddContactType(parser.getType())) {
|
if (!isAutoAddEnabled()) {
|
||||||
ContactInfo ci;
|
ContactInfo ci;
|
||||||
populateContactFromAdvert(ci, id, parser, timestamp);
|
memset(&ci, 0, sizeof(ci));
|
||||||
|
ci.id = id;
|
||||||
|
ci.out_path_len = -1; // initially out_path is unknown
|
||||||
|
StrHelper::strncpy(ci.name, parser.getName(), sizeof(ci.name));
|
||||||
|
ci.type = parser.getType();
|
||||||
|
if (parser.hasLatLon()) {
|
||||||
|
ci.gps_lat = parser.getIntLat();
|
||||||
|
ci.gps_lon = parser.getIntLon();
|
||||||
|
}
|
||||||
|
ci.last_advert_timestamp = timestamp;
|
||||||
|
ci.lastmod = getRTCClock()->getCurrentTime();
|
||||||
onDiscoveredContact(ci, true, packet->path_len, packet->path); // let UI know
|
onDiscoveredContact(ci, true, packet->path_len, packet->path); // let UI know
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
is_new = true;
|
is_new = true;
|
||||||
from = allocateContactSlot();
|
if (num_contacts < MAX_CONTACTS) {
|
||||||
if (from == NULL) {
|
from = &contacts[num_contacts++];
|
||||||
ContactInfo ci;
|
from->id = id;
|
||||||
populateContactFromAdvert(ci, id, parser, timestamp);
|
from->out_path_len = -1; // initially out_path is unknown
|
||||||
onDiscoveredContact(ci, true, packet->path_len, packet->path);
|
from->gps_lat = 0; // initially unknown GPS loc
|
||||||
onContactsFull();
|
from->gps_lon = 0;
|
||||||
MESH_DEBUG_PRINTLN("onAdvertRecv: unable to allocate contact slot for new contact");
|
from->sync_since = 0;
|
||||||
|
|
||||||
|
from->shared_secret_valid = false; // ecdh shared_secret will be calculated later on demand
|
||||||
|
} else {
|
||||||
|
MESH_DEBUG_PRINTLN("onAdvertRecv: contacts table is full!");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
populateContactFromAdvert(*from, id, parser, timestamp);
|
|
||||||
from->sync_since = 0;
|
|
||||||
from->shared_secret_valid = false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// update
|
// update
|
||||||
StrHelper::strncpy(from->name, parser.getName(), sizeof(from->name));
|
StrHelper::strncpy(from->name, parser.getName(), sizeof(from->name));
|
||||||
from->type = parser.getType();
|
from->type = parser.getType();
|
||||||
if (parser.hasLatLon()) {
|
if (parser.hasLatLon()) {
|
||||||
from->gps_lat = parser.getIntLat();
|
from->gps_lat = parser.getIntLat();
|
||||||
from->gps_lon = parser.getIntLon();
|
from->gps_lon = parser.getIntLon();
|
||||||
}
|
}
|
||||||
from->last_advert_timestamp = timestamp;
|
from->last_advert_timestamp = timestamp;
|
||||||
from->lastmod = getRTCClock()->getCurrentTime();
|
from->lastmod = getRTCClock()->getCurrentTime();
|
||||||
|
|
||||||
onDiscoveredContact(*from, is_new, packet->path_len, packet->path); // let UI know
|
onDiscoveredContact(*from, is_new, packet->path_len, packet->path); // let UI know
|
||||||
}
|
}
|
||||||
@@ -514,31 +477,6 @@ int BaseChatMesh::sendLogin(const ContactInfo& recipient, const char* password,
|
|||||||
return MSG_SEND_FAILED;
|
return MSG_SEND_FAILED;
|
||||||
}
|
}
|
||||||
|
|
||||||
int BaseChatMesh::sendAnonReq(const ContactInfo& recipient, const uint8_t* data, uint8_t len, uint32_t& tag, uint32_t& est_timeout) {
|
|
||||||
mesh::Packet* pkt;
|
|
||||||
{
|
|
||||||
uint8_t temp[MAX_PACKET_PAYLOAD];
|
|
||||||
tag = getRTCClock()->getCurrentTimeUnique();
|
|
||||||
memcpy(temp, &tag, 4); // tag to match later (also extra blob to help make packet_hash unique)
|
|
||||||
memcpy(&temp[4], data, len);
|
|
||||||
|
|
||||||
pkt = createAnonDatagram(PAYLOAD_TYPE_ANON_REQ, self_id, recipient.id, recipient.getSharedSecret(self_id), temp, 4 + len);
|
|
||||||
}
|
|
||||||
if (pkt) {
|
|
||||||
uint32_t t = _radio->getEstAirtimeFor(pkt->getRawLength());
|
|
||||||
if (recipient.out_path_len < 0) {
|
|
||||||
sendFloodScoped(recipient, pkt);
|
|
||||||
est_timeout = calcFloodTimeoutMillisFor(t);
|
|
||||||
return MSG_SEND_SENT_FLOOD;
|
|
||||||
} else {
|
|
||||||
sendDirect(pkt, recipient.out_path, recipient.out_path_len);
|
|
||||||
est_timeout = calcDirectTimeoutMillisFor(t, recipient.out_path_len);
|
|
||||||
return MSG_SEND_SENT_DIRECT;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return MSG_SEND_FAILED;
|
|
||||||
}
|
|
||||||
|
|
||||||
int BaseChatMesh::sendRequest(const ContactInfo& recipient, const uint8_t* req_data, uint8_t data_len, uint32_t& tag, uint32_t& est_timeout) {
|
int BaseChatMesh::sendRequest(const ContactInfo& recipient, const uint8_t* req_data, uint8_t data_len, uint32_t& tag, uint32_t& est_timeout) {
|
||||||
if (data_len > MAX_PACKET_PAYLOAD - 16) return MSG_SEND_FAILED;
|
if (data_len > MAX_PACKET_PAYLOAD - 16) return MSG_SEND_FAILED;
|
||||||
|
|
||||||
@@ -759,9 +697,10 @@ ContactInfo* BaseChatMesh::lookupContactByPubKey(const uint8_t* pub_key, int pre
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool BaseChatMesh::addContact(const ContactInfo& contact) {
|
bool BaseChatMesh::addContact(const ContactInfo& contact) {
|
||||||
ContactInfo* dest = allocateContactSlot();
|
if (num_contacts < MAX_CONTACTS) {
|
||||||
if (dest) {
|
auto dest = &contacts[num_contacts++];
|
||||||
*dest = contact;
|
*dest = contact;
|
||||||
|
|
||||||
dest->shared_secret_valid = false; // mark shared_secret as needing calculation
|
dest->shared_secret_valid = false; // mark shared_secret as needing calculation
|
||||||
return true; // success
|
return true; // success
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -88,17 +88,10 @@ protected:
|
|||||||
memset(connections, 0, sizeof(connections));
|
memset(connections, 0, sizeof(connections));
|
||||||
}
|
}
|
||||||
|
|
||||||
void bootstrapRTCfromContacts();
|
|
||||||
void resetContacts() { num_contacts = 0; }
|
void resetContacts() { num_contacts = 0; }
|
||||||
void populateContactFromAdvert(ContactInfo& ci, const mesh::Identity& id, const AdvertDataParser& parser, uint32_t timestamp);
|
|
||||||
ContactInfo* allocateContactSlot(); // helper to find slot for new contact
|
|
||||||
|
|
||||||
// 'UI' concepts, for sub-classes to implement
|
// 'UI' concepts, for sub-classes to implement
|
||||||
virtual bool isAutoAddEnabled() const { return true; }
|
virtual bool isAutoAddEnabled() const { return true; }
|
||||||
virtual bool shouldAutoAddContactType(uint8_t type) const { return true; }
|
|
||||||
virtual void onContactsFull() {};
|
|
||||||
virtual bool shouldOverwriteWhenFull() const { return false; }
|
|
||||||
virtual void onContactOverwrite(const uint8_t* pub_key) {};
|
|
||||||
virtual void onDiscoveredContact(ContactInfo& contact, bool is_new, uint8_t path_len, const uint8_t* path) = 0;
|
virtual void onDiscoveredContact(ContactInfo& contact, bool is_new, uint8_t path_len, const uint8_t* path) = 0;
|
||||||
virtual ContactInfo* processAck(const uint8_t *data) = 0;
|
virtual ContactInfo* processAck(const uint8_t *data) = 0;
|
||||||
virtual void onContactPathUpdated(const ContactInfo& contact) = 0;
|
virtual void onContactPathUpdated(const ContactInfo& contact) = 0;
|
||||||
@@ -148,7 +141,6 @@ public:
|
|||||||
int sendCommandData(const ContactInfo& recipient, uint32_t timestamp, uint8_t attempt, const char* text, uint32_t& est_timeout);
|
int sendCommandData(const ContactInfo& recipient, uint32_t timestamp, uint8_t attempt, const char* text, uint32_t& est_timeout);
|
||||||
bool sendGroupMessage(uint32_t timestamp, mesh::GroupChannel& channel, const char* sender_name, const char* text, int text_len);
|
bool sendGroupMessage(uint32_t timestamp, mesh::GroupChannel& channel, const char* sender_name, const char* text, int text_len);
|
||||||
int sendLogin(const ContactInfo& recipient, const char* password, uint32_t& est_timeout);
|
int sendLogin(const ContactInfo& recipient, const char* password, uint32_t& est_timeout);
|
||||||
int sendAnonReq(const ContactInfo& recipient, const uint8_t* data, uint8_t len, uint32_t& tag, uint32_t& est_timeout);
|
|
||||||
int sendRequest(const ContactInfo& recipient, uint8_t req_type, uint32_t& tag, uint32_t& est_timeout);
|
int sendRequest(const ContactInfo& recipient, uint8_t req_type, uint32_t& tag, uint32_t& est_timeout);
|
||||||
int sendRequest(const ContactInfo& recipient, const uint8_t* req_data, uint8_t data_len, uint32_t& tag, uint32_t& est_timeout);
|
int sendRequest(const ContactInfo& recipient, const uint8_t* req_data, uint8_t data_len, uint32_t& tag, uint32_t& est_timeout);
|
||||||
bool shareContactZeroHop(const ContactInfo& contact);
|
bool shareContactZeroHop(const ContactInfo& contact);
|
||||||
|
|||||||
@@ -14,14 +14,6 @@ static uint32_t _atoi(const char* sp) {
|
|||||||
return n;
|
return n;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool isValidName(const char *n) {
|
|
||||||
while (*n) {
|
|
||||||
if (*n == '[' || *n == ']' || *n == '/' || *n == '\\' || *n == ':' || *n == ',' || *n == '?' || *n == '*') return false;
|
|
||||||
n++;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void CommonCLI::loadPrefs(FILESYSTEM* fs) {
|
void CommonCLI::loadPrefs(FILESYSTEM* fs) {
|
||||||
if (fs->exists("/com_prefs")) {
|
if (fs->exists("/com_prefs")) {
|
||||||
loadPrefsInt(fs, "/com_prefs"); // new filename
|
loadPrefsInt(fs, "/com_prefs"); // new filename
|
||||||
@@ -80,8 +72,7 @@ void CommonCLI::loadPrefsInt(FILESYSTEM* fs, const char* filename) {
|
|||||||
file.read((uint8_t *)&_prefs->advert_loc_policy, sizeof (_prefs->advert_loc_policy)); // 161
|
file.read((uint8_t *)&_prefs->advert_loc_policy, sizeof (_prefs->advert_loc_policy)); // 161
|
||||||
file.read((uint8_t *)&_prefs->discovery_mod_timestamp, sizeof(_prefs->discovery_mod_timestamp)); // 162
|
file.read((uint8_t *)&_prefs->discovery_mod_timestamp, sizeof(_prefs->discovery_mod_timestamp)); // 162
|
||||||
file.read((uint8_t *)&_prefs->adc_multiplier, sizeof(_prefs->adc_multiplier)); // 166
|
file.read((uint8_t *)&_prefs->adc_multiplier, sizeof(_prefs->adc_multiplier)); // 166
|
||||||
file.read((uint8_t *)_prefs->owner_info, sizeof(_prefs->owner_info)); // 170
|
// 170
|
||||||
// 290
|
|
||||||
|
|
||||||
// sanitise bad pref values
|
// sanitise bad pref values
|
||||||
_prefs->rx_delay_base = constrain(_prefs->rx_delay_base, 0, 20.0f);
|
_prefs->rx_delay_base = constrain(_prefs->rx_delay_base, 0, 20.0f);
|
||||||
@@ -164,15 +155,12 @@ void CommonCLI::savePrefs(FILESYSTEM* fs) {
|
|||||||
file.write((uint8_t *)&_prefs->advert_loc_policy, sizeof(_prefs->advert_loc_policy)); // 161
|
file.write((uint8_t *)&_prefs->advert_loc_policy, sizeof(_prefs->advert_loc_policy)); // 161
|
||||||
file.write((uint8_t *)&_prefs->discovery_mod_timestamp, sizeof(_prefs->discovery_mod_timestamp)); // 162
|
file.write((uint8_t *)&_prefs->discovery_mod_timestamp, sizeof(_prefs->discovery_mod_timestamp)); // 162
|
||||||
file.write((uint8_t *)&_prefs->adc_multiplier, sizeof(_prefs->adc_multiplier)); // 166
|
file.write((uint8_t *)&_prefs->adc_multiplier, sizeof(_prefs->adc_multiplier)); // 166
|
||||||
file.write((uint8_t *)_prefs->owner_info, sizeof(_prefs->owner_info)); // 170
|
// 170
|
||||||
// 290
|
|
||||||
|
|
||||||
file.close();
|
file.close();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#define MIN_LOCAL_ADVERT_INTERVAL 60
|
|
||||||
|
|
||||||
void CommonCLI::savePrefs() {
|
void CommonCLI::savePrefs() {
|
||||||
if (_prefs->advert_interval * 2 < MIN_LOCAL_ADVERT_INTERVAL) {
|
if (_prefs->advert_interval * 2 < MIN_LOCAL_ADVERT_INTERVAL) {
|
||||||
_prefs->advert_interval = 0; // turn it off, now that device has been manually configured
|
_prefs->advert_interval = 0; // turn it off, now that device has been manually configured
|
||||||
@@ -197,6 +185,7 @@ void CommonCLI::handleCommand(uint32_t sender_timestamp, const char* command, ch
|
|||||||
if (memcmp(command, "reboot", 6) == 0) {
|
if (memcmp(command, "reboot", 6) == 0) {
|
||||||
_board->reboot(); // doesn't return
|
_board->reboot(); // doesn't return
|
||||||
} else if (memcmp(command, "advert", 6) == 0) {
|
} else if (memcmp(command, "advert", 6) == 0) {
|
||||||
|
// Keep "advert" as flood for backward compatibility
|
||||||
_callbacks->sendSelfAdvertisement(1500); // longer delay, give CLI response time to be sent first
|
_callbacks->sendSelfAdvertisement(1500); // longer delay, give CLI response time to be sent first
|
||||||
strcpy(reply, "OK - Advert sent");
|
strcpy(reply, "OK - Advert sent");
|
||||||
} else if (memcmp(command, "clock sync", 10) == 0) {
|
} else if (memcmp(command, "clock sync", 10) == 0) {
|
||||||
@@ -217,7 +206,7 @@ void CommonCLI::handleCommand(uint32_t sender_timestamp, const char* command, ch
|
|||||||
uint32_t now = getRTCClock()->getCurrentTime();
|
uint32_t now = getRTCClock()->getCurrentTime();
|
||||||
DateTime dt = DateTime(now);
|
DateTime dt = DateTime(now);
|
||||||
sprintf(reply, "%02d:%02d - %d/%d/%d UTC", dt.hour(), dt.minute(), dt.day(), dt.month(), dt.year());
|
sprintf(reply, "%02d:%02d - %d/%d/%d UTC", dt.hour(), dt.minute(), dt.day(), dt.month(), dt.year());
|
||||||
} else if (memcmp(command, "time ", 5) == 0) { // set time (to epoch seconds)
|
} else if (memcmp(command, "time ", 5) == 0) { // set time (to epoch seconds)
|
||||||
uint32_t secs = _atoi(&command[5]);
|
uint32_t secs = _atoi(&command[5]);
|
||||||
uint32_t curr = getRTCClock()->getCurrentTime();
|
uint32_t curr = getRTCClock()->getCurrentTime();
|
||||||
if (secs > curr) {
|
if (secs > curr) {
|
||||||
@@ -311,15 +300,6 @@ void CommonCLI::handleCommand(uint32_t sender_timestamp, const char* command, ch
|
|||||||
sprintf(reply, "> %d", (uint32_t)_prefs->flood_max);
|
sprintf(reply, "> %d", (uint32_t)_prefs->flood_max);
|
||||||
} else if (memcmp(config, "direct.txdelay", 14) == 0) {
|
} else if (memcmp(config, "direct.txdelay", 14) == 0) {
|
||||||
sprintf(reply, "> %s", StrHelper::ftoa(_prefs->direct_tx_delay_factor));
|
sprintf(reply, "> %s", StrHelper::ftoa(_prefs->direct_tx_delay_factor));
|
||||||
} else if (memcmp(config, "owner.info", 10) == 0) {
|
|
||||||
*reply++ = '>';
|
|
||||||
*reply++ = ' ';
|
|
||||||
const char* sp = _prefs->owner_info;
|
|
||||||
while (*sp) {
|
|
||||||
*reply++ = (*sp == '\n') ? '|' : *sp; // translate newline back to orig '|'
|
|
||||||
sp++;
|
|
||||||
}
|
|
||||||
*reply = 0; // set null terminator
|
|
||||||
} else if (memcmp(config, "tx", 2) == 0 && (config[2] == 0 || config[2] == ' ')) {
|
} else if (memcmp(config, "tx", 2) == 0 && (config[2] == 0 || config[2] == ' ')) {
|
||||||
sprintf(reply, "> %d", (uint32_t) _prefs->tx_power_dbm);
|
sprintf(reply, "> %d", (uint32_t) _prefs->tx_power_dbm);
|
||||||
} else if (memcmp(config, "freq", 4) == 0) {
|
} else if (memcmp(config, "freq", 4) == 0) {
|
||||||
@@ -394,8 +374,9 @@ void CommonCLI::handleCommand(uint32_t sender_timestamp, const char* command, ch
|
|||||||
strcpy(reply, "OK");
|
strcpy(reply, "OK");
|
||||||
} else if (memcmp(config, "flood.advert.interval ", 22) == 0) {
|
} else if (memcmp(config, "flood.advert.interval ", 22) == 0) {
|
||||||
int hours = _atoi(&config[22]);
|
int hours = _atoi(&config[22]);
|
||||||
if ((hours > 0 && hours < 3) || (hours > 48)) {
|
if ((hours > 0 && hours < MIN_FLOOD_ADVERT_INTERVAL) || (hours > MAX_FLOOD_ADVERT_INTERVAL)) {
|
||||||
strcpy(reply, "Error: interval range is 3-48 hours");
|
sprintf(reply, "Error: interval range is %d-%d hours", MIN_FLOOD_ADVERT_INTERVAL,
|
||||||
|
MAX_FLOOD_ADVERT_INTERVAL);
|
||||||
} else {
|
} else {
|
||||||
_prefs->flood_advert_interval = (uint8_t)(hours);
|
_prefs->flood_advert_interval = (uint8_t)(hours);
|
||||||
_callbacks->updateFloodAdvertTimer();
|
_callbacks->updateFloodAdvertTimer();
|
||||||
@@ -404,8 +385,9 @@ void CommonCLI::handleCommand(uint32_t sender_timestamp, const char* command, ch
|
|||||||
}
|
}
|
||||||
} else if (memcmp(config, "advert.interval ", 16) == 0) {
|
} else if (memcmp(config, "advert.interval ", 16) == 0) {
|
||||||
int mins = _atoi(&config[16]);
|
int mins = _atoi(&config[16]);
|
||||||
if ((mins > 0 && mins < MIN_LOCAL_ADVERT_INTERVAL) || (mins > 240)) {
|
if ((mins > 0 && mins < MIN_LOCAL_ADVERT_INTERVAL) || (mins > MAX_LOCAL_ADVERT_INTERVAL)) {
|
||||||
sprintf(reply, "Error: interval range is %d-240 minutes", MIN_LOCAL_ADVERT_INTERVAL);
|
sprintf(reply, "Error: interval range is %d-%d minutes",MIN_LOCAL_ADVERT_INTERVAL,
|
||||||
|
MAX_LOCAL_ADVERT_INTERVAL);
|
||||||
} else {
|
} else {
|
||||||
_prefs->advert_interval = (uint8_t)(mins / 2);
|
_prefs->advert_interval = (uint8_t)(mins / 2);
|
||||||
_callbacks->updateAdvertTimer();
|
_callbacks->updateAdvertTimer();
|
||||||
@@ -429,13 +411,9 @@ void CommonCLI::handleCommand(uint32_t sender_timestamp, const char* command, ch
|
|||||||
strcpy(reply, "Error, invalid key");
|
strcpy(reply, "Error, invalid key");
|
||||||
}
|
}
|
||||||
} else if (memcmp(config, "name ", 5) == 0) {
|
} else if (memcmp(config, "name ", 5) == 0) {
|
||||||
if (isValidName(&config[5])) {
|
StrHelper::strncpy(_prefs->node_name, &config[5], sizeof(_prefs->node_name));
|
||||||
StrHelper::strncpy(_prefs->node_name, &config[5], sizeof(_prefs->node_name));
|
savePrefs();
|
||||||
savePrefs();
|
strcpy(reply, "OK");
|
||||||
strcpy(reply, "OK");
|
|
||||||
} else {
|
|
||||||
strcpy(reply, "Error, bad chars");
|
|
||||||
}
|
|
||||||
} else if (memcmp(config, "repeat ", 7) == 0) {
|
} else if (memcmp(config, "repeat ", 7) == 0) {
|
||||||
_prefs->disable_fwd = memcmp(&config[7], "off", 3) == 0;
|
_prefs->disable_fwd = memcmp(&config[7], "off", 3) == 0;
|
||||||
savePrefs();
|
savePrefs();
|
||||||
@@ -502,16 +480,6 @@ void CommonCLI::handleCommand(uint32_t sender_timestamp, const char* command, ch
|
|||||||
} else {
|
} else {
|
||||||
strcpy(reply, "Error, cannot be negative");
|
strcpy(reply, "Error, cannot be negative");
|
||||||
}
|
}
|
||||||
} else if (memcmp(config, "owner.info ", 11) == 0) {
|
|
||||||
config += 11;
|
|
||||||
char *dp = _prefs->owner_info;
|
|
||||||
while (*config && dp - _prefs->owner_info < sizeof(_prefs->owner_info)-1) {
|
|
||||||
*dp++ = (*config == '|') ? '\n' : *config; // translate '|' to newline chars
|
|
||||||
config++;
|
|
||||||
}
|
|
||||||
*dp = 0;
|
|
||||||
savePrefs();
|
|
||||||
strcpy(reply, "OK");
|
|
||||||
} else if (memcmp(config, "tx ", 3) == 0) {
|
} else if (memcmp(config, "tx ", 3) == 0) {
|
||||||
_prefs->tx_power_dbm = atoi(&config[3]);
|
_prefs->tx_power_dbm = atoi(&config[3]);
|
||||||
savePrefs();
|
savePrefs();
|
||||||
|
|||||||
@@ -50,7 +50,6 @@ struct NodePrefs { // persisted to file
|
|||||||
uint8_t advert_loc_policy;
|
uint8_t advert_loc_policy;
|
||||||
uint32_t discovery_mod_timestamp;
|
uint32_t discovery_mod_timestamp;
|
||||||
float adc_multiplier;
|
float adc_multiplier;
|
||||||
char owner_info[120];
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class CommonCLICallbacks {
|
class CommonCLICallbacks {
|
||||||
@@ -60,7 +59,7 @@ public:
|
|||||||
virtual const char* getBuildDate() = 0;
|
virtual const char* getBuildDate() = 0;
|
||||||
virtual const char* getRole() = 0;
|
virtual const char* getRole() = 0;
|
||||||
virtual bool formatFileSystem() = 0;
|
virtual bool formatFileSystem() = 0;
|
||||||
virtual void sendSelfAdvertisement(int delay_millis) = 0;
|
virtual void sendSelfAdvertisement(int delay_millis, bool flood = true) = 0;
|
||||||
virtual void updateAdvertTimer() = 0;
|
virtual void updateAdvertTimer() = 0;
|
||||||
virtual void updateFloodAdvertTimer() = 0;
|
virtual void updateFloodAdvertTimer() = 0;
|
||||||
virtual void setLoggingOn(bool enable) = 0;
|
virtual void setLoggingOn(bool enable) = 0;
|
||||||
|
|||||||
@@ -9,9 +9,8 @@ RegionMap::RegionMap(TransportKeyStore& store) : _store(&store) {
|
|||||||
strcpy(wildcard.name, "*");
|
strcpy(wildcard.name, "*");
|
||||||
}
|
}
|
||||||
|
|
||||||
bool RegionMap::is_name_char(uint8_t c) {
|
bool RegionMap::is_name_char(char c) {
|
||||||
// accept all alpha-num or accented characters, but exclude most punctuation chars
|
return (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') || (c >= '0' && c <= '9') || c == '-' || c == '.' || c == '_' || c == '#';
|
||||||
return c == '-' || c == '#' || (c >= '0' && c <= '9') || c >= 'A';
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static File openWrite(FILESYSTEM* _fs, const char* filename) {
|
static File openWrite(FILESYSTEM* _fs, const char* filename) {
|
||||||
@@ -25,12 +24,12 @@ static File openWrite(FILESYSTEM* _fs, const char* filename) {
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
bool RegionMap::load(FILESYSTEM* _fs, const char* path) {
|
bool RegionMap::load(FILESYSTEM* _fs) {
|
||||||
if (_fs->exists(path ? path : "/regions2")) {
|
if (_fs->exists("/regions2")) {
|
||||||
#if defined(RP2040_PLATFORM)
|
#if defined(RP2040_PLATFORM)
|
||||||
File file = _fs->open(path ? path : "/regions2", "r");
|
File file = _fs->open("/regions2", "r");
|
||||||
#else
|
#else
|
||||||
File file = _fs->open(path ? path : "/regions2");
|
File file = _fs->open("/regions2");
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (file) {
|
if (file) {
|
||||||
@@ -68,8 +67,8 @@ bool RegionMap::load(FILESYSTEM* _fs, const char* path) {
|
|||||||
return false; // failed
|
return false; // failed
|
||||||
}
|
}
|
||||||
|
|
||||||
bool RegionMap::save(FILESYSTEM* _fs, const char* path) {
|
bool RegionMap::save(FILESYSTEM* _fs) {
|
||||||
File file = openWrite(_fs, path ? path : "/regions2");
|
File file = openWrite(_fs, "/regions2");
|
||||||
if (file) {
|
if (file) {
|
||||||
uint8_t pad[128];
|
uint8_t pad[128];
|
||||||
memset(pad, 0, sizeof(pad));
|
memset(pad, 0, sizeof(pad));
|
||||||
@@ -236,27 +235,3 @@ void RegionMap::printChildRegions(int indent, const RegionEntry* parent, Stream&
|
|||||||
void RegionMap::exportTo(Stream& out) const {
|
void RegionMap::exportTo(Stream& out) const {
|
||||||
printChildRegions(0, &wildcard, out); // recursive
|
printChildRegions(0, &wildcard, out); // recursive
|
||||||
}
|
}
|
||||||
|
|
||||||
int RegionMap::exportNamesTo(char *dest, int max_len, uint8_t mask) {
|
|
||||||
char *dp = dest;
|
|
||||||
if ((wildcard.flags & mask) == 0) {
|
|
||||||
*dp++ = '*';
|
|
||||||
*dp++ = ',';
|
|
||||||
}
|
|
||||||
|
|
||||||
for (int i = 0; i < num_regions; i++) {
|
|
||||||
auto region = ®ions[i];
|
|
||||||
if ((region->flags & mask) == 0) { // region allowed? (per 'mask' param)
|
|
||||||
int len = strlen(region->name);
|
|
||||||
if ((dp - dest) + len + 2 < max_len) { // only append if name will fit
|
|
||||||
memcpy(dp, region->name, len);
|
|
||||||
dp += len;
|
|
||||||
*dp++ = ',';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (dp > dest) { dp--; } // don't include trailing comma
|
|
||||||
|
|
||||||
*dp = 0; // set null terminator
|
|
||||||
return dp - dest; // return length
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -30,10 +30,10 @@ class RegionMap {
|
|||||||
public:
|
public:
|
||||||
RegionMap(TransportKeyStore& store);
|
RegionMap(TransportKeyStore& store);
|
||||||
|
|
||||||
static bool is_name_char(uint8_t c);
|
static bool is_name_char(char c);
|
||||||
|
|
||||||
bool load(FILESYSTEM* _fs, const char* path=NULL);
|
bool load(FILESYSTEM* _fs);
|
||||||
bool save(FILESYSTEM* _fs, const char* path=NULL);
|
bool save(FILESYSTEM* _fs);
|
||||||
|
|
||||||
RegionEntry* putRegion(const char* name, uint16_t parent_id, uint16_t id = 0);
|
RegionEntry* putRegion(const char* name, uint16_t parent_id, uint16_t id = 0);
|
||||||
RegionEntry* findMatch(mesh::Packet* packet, uint8_t mask);
|
RegionEntry* findMatch(mesh::Packet* packet, uint8_t mask);
|
||||||
@@ -47,9 +47,6 @@ public:
|
|||||||
bool clear();
|
bool clear();
|
||||||
void resetFrom(const RegionMap& src) { num_regions = 0; next_id = src.next_id; }
|
void resetFrom(const RegionMap& src) { num_regions = 0; next_id = src.next_id; }
|
||||||
int getCount() const { return num_regions; }
|
int getCount() const { return num_regions; }
|
||||||
const RegionEntry* getByIdx(int i) const { return ®ions[i]; }
|
|
||||||
const RegionEntry* getRoot() const { return &wildcard; }
|
|
||||||
int exportNamesTo(char *dest, int max_len, uint8_t mask);
|
|
||||||
|
|
||||||
void exportTo(Stream& out) const;
|
void exportTo(Stream& out) const;
|
||||||
};
|
};
|
||||||
|
|||||||
64
tools/maint/patch_and_build_hansemesh_fw.sh
Executable file
64
tools/maint/patch_and_build_hansemesh_fw.sh
Executable file
@@ -0,0 +1,64 @@
|
|||||||
|
#!/bin/bash # Note: switched to bash for process substitution support
|
||||||
|
|
||||||
|
export PATH="$HOME/.platformio/penv/bin:$PATH"
|
||||||
|
|
||||||
|
LOGFILE="$PWD/meshcore-evo-fw.log"
|
||||||
|
FIRMWARE_VERSION="v1.11_evo"
|
||||||
|
FIRMWARE_BUILD_DATE=$(date '+%d-%b-%Y')
|
||||||
|
|
||||||
|
collect_bin_files(){
|
||||||
|
DEST_DIR="./firmwares"
|
||||||
|
mkdir -p "$DEST_DIR"
|
||||||
|
BUILD_DIR=".pio/build"
|
||||||
|
|
||||||
|
if [ ! -d "$BUILD_DIR" ]; then
|
||||||
|
echo "Error: $BUILD_DIR not found. Did you run the build process?"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "Copying firmware files to $DEST_DIR..."
|
||||||
|
|
||||||
|
for target_path in "$BUILD_DIR"/*/; do
|
||||||
|
echo $target_path
|
||||||
|
target_name=$(basename "$target_path")
|
||||||
|
# if ls "$target_path"*.bin >/dev/null 2>&1; then
|
||||||
|
for bin_file in "$target_path"*firmware*.{uf2,bin,zip}; do
|
||||||
|
filename=$(basename "$bin_file")
|
||||||
|
new_filename="${target_name}_${FIRMWARE_VERSION}_${FIRMWARE_BUILD_DATE}_${filename}"
|
||||||
|
cp "$bin_file" "$DEST_DIR/$new_filename"
|
||||||
|
echo "Done: $new_filename"
|
||||||
|
done
|
||||||
|
# fi
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
|
# Everything after this line goes to BOTH console and logfile
|
||||||
|
exec > >(tee -a "$LOGFILE") 2>&1
|
||||||
|
|
||||||
|
echo "-------------------- Build start ----------------"
|
||||||
|
date
|
||||||
|
echo "-------------------------------------------------"
|
||||||
|
|
||||||
|
# apply patches
|
||||||
|
# ./tools/maint/apply_patches.sh 1199 1338 1297
|
||||||
|
|
||||||
|
# build all repeater firmwares, the will be in .out
|
||||||
|
FIRMWARE_VERSION="v1.11_evo" ./build.sh build-repeater-firmwares
|
||||||
|
|
||||||
|
# build single firmwares
|
||||||
|
#FIRMWARE_VERSION=$FIRMWARE_VERSION FIRMWARE_BUILD_DATE=$FIRMWARE_BUILD_DATE ./build.sh build-firmware ProMicro_repeater
|
||||||
|
#FIRMWARE_VERSION=$FIRMWARE_VERSION FIRMWARE_BUILD_DATE=$FIRMWARE_BUILD_DATE ./build.sh build-firmware RAK_4631_repeater
|
||||||
|
#FIRMWARE_VERSION=$FIRMWARE_VERSION FIRMWARE_BUILD_DATE=$FIRMWARE_BUILD_DATE ./build.sh build-firmware heltec_v4_repeater
|
||||||
|
#FIRMWARE_VERSION=$FIRMWARE_VERSION FIRMWARE_BUILD_DATE=$FIRMWARE_BUILD_DATE ./build.sh build-firmware Heltec_v3_repeater
|
||||||
|
#FIRMWARE_VERSION=$FIRMWARE_VERSION FIRMWARE_BUILD_DATE=$FIRMWARE_BUILD_DATE ./build.sh build-firmware Xiao_nrf52_repeater
|
||||||
|
#FIRMWARE_VERSION=$FIRMWARE_VERSION FIRMWARE_BUILD_DATE=$FIRMWARE_BUILD_DATE ./build.sh build-firmware LilyGo_T3S3_sx1262_repeater
|
||||||
|
#FIRMWARE_VERSION=$FIRMWARE_VERSION FIRMWARE_BUILD_DATE=$FIRMWARE_BUILD_DATE ./build.sh build-firmware Heltec_t114_without_display_repeater
|
||||||
|
#FIRMWARE_VERSION=$FIRMWARE_VERSION FIRMWARE_BUILD_DATE=$FIRMWARE_BUILD_DATE ./build.sh build-firmware Heltec_t114_repeater
|
||||||
|
#collect_bin_files
|
||||||
|
|
||||||
|
|
||||||
|
echo "-------------------- Build end ------------------"
|
||||||
|
date
|
||||||
|
echo "-------------------------------------------------"
|
||||||
|
|
||||||
|
#grep -E " SUCCESS | FAILED " hansemesh_fw.log
|
||||||
@@ -323,7 +323,7 @@ lib_deps =
|
|||||||
extends = Heltec_lora32_v3
|
extends = Heltec_lora32_v3
|
||||||
build_flags =
|
build_flags =
|
||||||
${Heltec_lora32_v3.build_flags}
|
${Heltec_lora32_v3.build_flags}
|
||||||
-D MAX_CONTACTS=350
|
-D MAX_CONTACTS=140
|
||||||
-D MAX_GROUP_CHANNELS=40
|
-D MAX_GROUP_CHANNELS=40
|
||||||
; NOTE: DO NOT ENABLE --> -D MESH_PACKET_LOGGING=1
|
; NOTE: DO NOT ENABLE --> -D MESH_PACKET_LOGGING=1
|
||||||
; NOTE: DO NOT ENABLE --> -D MESH_DEBUG=1
|
; NOTE: DO NOT ENABLE --> -D MESH_DEBUG=1
|
||||||
|
|||||||
@@ -1,5 +1,8 @@
|
|||||||
[ikoka_handheld_nrf]
|
[ikoka_nrf52]
|
||||||
extends = nrf52_base
|
extends = Xiao_nrf52
|
||||||
|
lib_deps = ${nrf52_base.lib_deps}
|
||||||
|
${sensor_base.lib_deps}
|
||||||
|
densaugeo/base64 @ ~1.4.0
|
||||||
build_flags = ${nrf52_base.build_flags}
|
build_flags = ${nrf52_base.build_flags}
|
||||||
${sensor_base.build_flags}
|
${sensor_base.build_flags}
|
||||||
-I lib/nrf52/s140_nrf52_7.3.0_API/include
|
-I lib/nrf52/s140_nrf52_7.3.0_API/include
|
||||||
@@ -23,15 +26,12 @@ build_flags = ${nrf52_base.build_flags}
|
|||||||
build_src_filter = ${nrf52_base.build_src_filter}
|
build_src_filter = ${nrf52_base.build_src_filter}
|
||||||
+<../variants/ikoka_handheld_nrf>
|
+<../variants/ikoka_handheld_nrf>
|
||||||
+<helpers/sensors>
|
+<helpers/sensors>
|
||||||
lib_deps = ${nrf52_base.lib_deps}
|
|
||||||
${sensor_base.lib_deps}
|
|
||||||
densaugeo/base64 @ ~1.4.0
|
|
||||||
|
|
||||||
# larger screen has a different driver, this is for the 0.96 inch
|
# larger screen has a different driver, this is for the 0.96 inch
|
||||||
[ikoka_handheld_nrf_ssd1306_companion]
|
[ikoka_nrf52_ssd1306_companion]
|
||||||
lib_deps = ${ikoka_handheld_nrf.lib_deps}
|
lib_deps = ${ikoka_nrf52.lib_deps}
|
||||||
adafruit/Adafruit SSD1306 @ ^2.5.13
|
adafruit/Adafruit SSD1306 @ ^2.5.13
|
||||||
build_flags = ${ikoka_handheld_nrf.build_flags}
|
build_flags = ${ikoka_nrf52.build_flags}
|
||||||
-D DISPLAY_CLASS=SSD1306Display
|
-D DISPLAY_CLASS=SSD1306Display
|
||||||
-D DISPLAY_ROTATION=0
|
-D DISPLAY_ROTATION=0
|
||||||
-D PIN_WIRE_SCL=D6
|
-D PIN_WIRE_SCL=D6
|
||||||
@@ -42,62 +42,62 @@ build_flags = ${ikoka_handheld_nrf.build_flags}
|
|||||||
-D OFFLINE_QUEUE_SIZE=256
|
-D OFFLINE_QUEUE_SIZE=256
|
||||||
-D QSPIFLASH=1
|
-D QSPIFLASH=1
|
||||||
-I examples/companion_radio/ui-new
|
-I examples/companion_radio/ui-new
|
||||||
build_src_filter = ${ikoka_handheld_nrf.build_src_filter}
|
build_src_filter = ${ikoka_nrf52.build_src_filter}
|
||||||
+<helpers/ui/SSD1306Display.cpp>
|
+<helpers/ui/SSD1306Display.cpp>
|
||||||
+<../examples/companion_radio/ui-new/UITask.cpp>
|
+<../examples/companion_radio/ui-new/UITask.cpp>
|
||||||
+<../examples/companion_radio/*.cpp>
|
+<../examples/companion_radio/*.cpp>
|
||||||
|
|
||||||
[env:ikoka_handheld_nrf_e22_30dbm_096_companion_radio_ble]
|
[env:ikoka_handheld_nrf_e22_30dbm_096_companion_radio_ble]
|
||||||
extends = ikoka_nrf52
|
extends = ikoka_nrf52
|
||||||
build_flags = ${ikoka_handheld_nrf_ssd1306_companion.build_flags}
|
build_flags = ${ikoka_nrf52_ssd1306_companion.build_flags}
|
||||||
-D BLE_PIN_CODE=123456
|
-D BLE_PIN_CODE=123456
|
||||||
-D LORA_TX_POWER=20
|
-D LORA_TX_POWER=20
|
||||||
build_src_filter = ${ikoka_handheld_nrf_ssd1306_companion.build_src_filter}
|
build_src_filter = ${ikoka_nrf52_ssd1306_companion.build_src_filter}
|
||||||
+<helpers/nrf52/SerialBLEInterface.cpp>
|
+<helpers/nrf52/SerialBLEInterface.cpp>
|
||||||
|
|
||||||
[env:ikoka_handheld_nrf_e22_30dbm_096_rotated_companion_radio_ble]
|
[env:ikoka_handheld_nrf_e22_30dbm_096_rotated_companion_radio_ble]
|
||||||
extends = ikoka_nrf52
|
extends = ikoka_nrf52
|
||||||
build_flags = ${ikoka_handheld_nrf_ssd1306_companion.build_flags}
|
build_flags = ${ikoka_nrf52_ssd1306_companion.build_flags}
|
||||||
-D BLE_PIN_CODE=123456
|
-D BLE_PIN_CODE=123456
|
||||||
-D LORA_TX_POWER=20
|
-D LORA_TX_POWER=20
|
||||||
-D DISPLAY_ROTATION=2
|
-D DISPLAY_ROTATION=2
|
||||||
build_src_filter = ${ikoka_handheld_nrf_ssd1306_companion.build_src_filter}
|
build_src_filter = ${ikoka_nrf52_ssd1306_companion.build_src_filter}
|
||||||
+<helpers/nrf52/SerialBLEInterface.cpp>
|
+<helpers/nrf52/SerialBLEInterface.cpp>
|
||||||
|
|
||||||
[env:ikoka_handheld_nrf_e22_30dbm_096_companion_radio_usb]
|
[env:ikoka_handheld_nrf_e22_30dbm_096_companion_radio_usb]
|
||||||
extends = ikoka_nrf52
|
extends = ikoka_nrf52
|
||||||
build_flags = ${ikoka_handheld_nrf_ssd1306_companion.build_flags}
|
build_flags = ${ikoka_nrf52_ssd1306_companion.build_flags}
|
||||||
-D LORA_TX_POWER=20
|
-D LORA_TX_POWER=20
|
||||||
build_src_filter = ${ikoka_handheld_nrf_ssd1306_companion.build_src_filter}
|
build_src_filter = ${ikoka_nrf52_ssd1306_companion.build_src_filter}
|
||||||
|
|
||||||
[env:ikoka_handheld_nrf_e22_30dbm_096_rotated_companion_radio_usb]
|
[env:ikoka_handheld_nrf_e22_30dbm_096_rotated_companion_radio_usb]
|
||||||
extends = ikoka_nrf52
|
extends = ikoka_nrf52
|
||||||
build_flags = ${ikoka_handheld_nrf_ssd1306_companion.build_flags}
|
build_flags = ${ikoka_nrf52_ssd1306_companion.build_flags}
|
||||||
-D LORA_TX_POWER=20
|
-D LORA_TX_POWER=20
|
||||||
-D DISPLAY_ROTATION=2
|
-D DISPLAY_ROTATION=2
|
||||||
build_src_filter = ${ikoka_handheld_nrf_ssd1306_companion.build_src_filter}
|
build_src_filter = ${ikoka_nrf52_ssd1306_companion.build_src_filter}
|
||||||
|
|
||||||
[env:ikoka_handheld_nrf_e22_30dbm_repeater]
|
[env:ikoka_handheld_nrf_e22_30dbm_repeater]
|
||||||
extends = ikoka_nrf52
|
extends = ikoka_nrf52
|
||||||
build_flags =
|
build_flags =
|
||||||
${ikoka_handheld_nrf.build_flags}
|
${ikoka_nrf52.build_flags}
|
||||||
-D ADVERT_NAME='"ikoka_handheld Repeater"'
|
-D ADVERT_NAME='"ikoka_handheld Repeater"'
|
||||||
-D ADVERT_LAT=0.0
|
-D ADVERT_LAT=0.0
|
||||||
-D ADVERT_LON=0.0
|
-D ADVERT_LON=0.0
|
||||||
-D ADMIN_PASSWORD='"password"'
|
-D ADMIN_PASSWORD='"password"'
|
||||||
-D MAX_NEIGHBOURS=50
|
-D MAX_NEIGHBOURS=50
|
||||||
-D LORA_TX_POWER=20
|
-D LORA_TX_POWER=20
|
||||||
build_src_filter = ${ikoka_handheld_nrf.build_src_filter}
|
build_src_filter = ${ikoka_nrf52.build_src_filter}
|
||||||
+<../examples/simple_repeater/*.cpp>
|
+<../examples/simple_repeater/*.cpp>
|
||||||
|
|
||||||
[env:ikoka_handheld_nrf_e22_30dbm_room_server]
|
[env:ikoka_handheld_nrf_e22_30dbm_room_server]
|
||||||
extends = ikoka_nrf52
|
extends = ikoka_nrf52
|
||||||
build_flags =
|
build_flags =
|
||||||
${ikoka_handheld_nrf.build_flags}
|
${ikoka_nrf52.build_flags}
|
||||||
-D ADVERT_NAME='"ikoka_handheld Room"'
|
-D ADVERT_NAME='"ikoka_handheld Room"'
|
||||||
-D ADVERT_LAT=0.0
|
-D ADVERT_LAT=0.0
|
||||||
-D ADVERT_LON=0.0
|
-D ADVERT_LON=0.0
|
||||||
-D ADMIN_PASSWORD='"password"'
|
-D ADMIN_PASSWORD='"password"'
|
||||||
-D LORA_TX_POWER=20
|
-D LORA_TX_POWER=20
|
||||||
build_src_filter = ${ikoka_handheld_nrf.build_src_filter}
|
build_src_filter = ${ikoka_nrf52.build_src_filter}
|
||||||
+<../examples/simple_room_server/*.cpp>
|
+<../examples/simple_room_server/*.cpp>
|
||||||
|
|||||||
@@ -1,124 +1,151 @@
|
|||||||
[ikoka_nano_nrf]
|
[nrf52840_xiao]
|
||||||
extends = nrf52_base
|
extends = nrf52_base
|
||||||
|
platform_packages =
|
||||||
|
toolchain-gccarmnoneeabi@~1.100301.0
|
||||||
|
framework-arduinoadafruitnrf52
|
||||||
board = seeed-xiao-afruitnrf52-nrf52840
|
board = seeed-xiao-afruitnrf52-nrf52840
|
||||||
board_build.ldscript = boards/nrf52840_s140_v7.ld
|
board_build.ldscript = boards/nrf52840_s140_v7.ld
|
||||||
build_flags = ${nrf52_base.build_flags}
|
build_flags = ${nrf52_base.build_flags}
|
||||||
${sensor_base.build_flags}
|
|
||||||
-D NRF52_PLATFORM -D XIAO_NRF52
|
-D NRF52_PLATFORM -D XIAO_NRF52
|
||||||
-I lib/nrf52/s140_nrf52_7.3.0_API/include
|
-I lib/nrf52/s140_nrf52_7.3.0_API/include
|
||||||
-I lib/nrf52/s140_nrf52_7.3.0_API/include/nrf52
|
-I lib/nrf52/s140_nrf52_7.3.0_API/include/nrf52
|
||||||
|
lib_ignore =
|
||||||
|
BluetoothOTA
|
||||||
|
lvgl
|
||||||
|
lib5b4
|
||||||
|
lib_deps =
|
||||||
|
${nrf52_base.lib_deps}
|
||||||
|
rweather/Crypto @ ^0.4.0
|
||||||
|
adafruit/Adafruit INA3221 Library @ ^1.0.1
|
||||||
|
adafruit/Adafruit INA219 @ ^1.2.3
|
||||||
|
adafruit/Adafruit AHTX0 @ ^2.0.5
|
||||||
|
adafruit/Adafruit BME280 Library @ ^2.3.0
|
||||||
|
adafruit/Adafruit SSD1306 @ ^2.5.13
|
||||||
|
|
||||||
|
[ikoka_nano_nrf_baseboard]
|
||||||
|
extends = nrf52840_xiao
|
||||||
|
;board_build.ldscript = boards/nrf52840_s140_v7.ld
|
||||||
|
build_flags = ${nrf52840_xiao.build_flags}
|
||||||
|
-D P_LORA_TX_LED=11
|
||||||
-I variants/ikoka_nano_nrf
|
-I variants/ikoka_nano_nrf
|
||||||
-I src/helpers/nrf52
|
-I src/helpers/nrf52
|
||||||
-D P_LORA_TX_LED=11
|
|
||||||
-D DISPLAY_CLASS=NullDisplayDriver
|
-D DISPLAY_CLASS=NullDisplayDriver
|
||||||
-D RADIO_CLASS=CustomSX1262
|
-D RADIO_CLASS=CustomSX1262
|
||||||
-D WRAPPER_CLASS=CustomSX1262Wrapper
|
-D WRAPPER_CLASS=CustomSX1262Wrapper
|
||||||
-D P_LORA_DIO_1=D1
|
-D P_LORA_DIO_1=D1
|
||||||
-D P_LORA_BUSY=D2
|
; -D P_LORA_BUSY=D3
|
||||||
-D P_LORA_RESET=D3
|
-D P_LORA_BUSY=D2 ; specific to ikoka nano variant.
|
||||||
-D P_LORA_NSS=D0
|
; -D P_LORA_RESET=D2
|
||||||
|
-D P_LORA_RESET=D3 ; specific to ikoka nano variant.
|
||||||
|
; -D P_LORA_NSS=D4
|
||||||
|
-D P_LORA_NSS=D0 ; specific to ikoka nano variant.
|
||||||
|
; -D SX126X_RXEN=D5
|
||||||
-D SX126X_RXEN=D7
|
-D SX126X_RXEN=D7
|
||||||
-D SX126X_TXEN=RADIOLIB_NC
|
-D SX126X_TXEN=RADIOLIB_NC
|
||||||
-D SX126X_DIO2_AS_RF_SWITCH=1
|
-D SX126X_DIO2_AS_RF_SWITCH=1
|
||||||
-D SX126X_DIO3_TCXO_VOLTAGE=1.8
|
-D SX126X_DIO3_TCXO_VOLTAGE=1.8
|
||||||
-D SX126X_CURRENT_LIMIT=140
|
-D SX126X_CURRENT_LIMIT=140
|
||||||
-D SX126X_RX_BOOSTED_GAIN=1
|
-D SX126X_RX_BOOSTED_GAIN=1
|
||||||
-D PIN_WIRE_SCL=5
|
-D PIN_WIRE_SCL=5 ; specific to ikoka nano variant.
|
||||||
-D PIN_WIRE_SDA=4
|
-D PIN_WIRE_SDA=4 ; specific to ikoka nano variant.
|
||||||
-UENV_INCLUDE_GPS
|
-D ENV_INCLUDE_AHTX0=1
|
||||||
|
-D ENV_INCLUDE_BME280=1
|
||||||
|
-D ENV_INCLUDE_INA3221=1
|
||||||
|
-D ENV_INCLUDE_INA219=1
|
||||||
debug_tool = jlink
|
debug_tool = jlink
|
||||||
upload_protocol = nrfutil
|
upload_protocol = nrfutil
|
||||||
lib_deps = ${nrf52_base.lib_deps}
|
|
||||||
${sensor_base.lib_deps}
|
|
||||||
|
;;; abstracted hardware variants
|
||||||
|
|
||||||
[ikoka_nano_nrf_e22_22dbm]
|
[ikoka_nano_nrf_e22_22dbm]
|
||||||
extends = ikoka_nano_nrf
|
extends = ikoka_nano_nrf_baseboard
|
||||||
; No PA in this model, full 22dBm
|
; No PA in this model, full 22dBm
|
||||||
build_flags =
|
build_flags =
|
||||||
${ikoka_nano_nrf.build_flags}
|
${ikoka_nano_nrf_baseboard.build_flags}
|
||||||
-D MANUFACTURER_STRING='"Ikoka Nano-E22-22dBm (Xiao_nrf52)"'
|
-D MANUFACTURER_STRING='"Ikoka Nano-E22-22dBm (Xiao_nrf52)"'
|
||||||
-D LORA_TX_POWER=22
|
-D LORA_TX_POWER=22
|
||||||
build_src_filter = ${ikoka_nano_nrf.build_src_filter}
|
build_src_filter = ${nrf52840_xiao.build_src_filter}
|
||||||
+<helpers/*.cpp>
|
+<helpers/*.cpp>
|
||||||
+<helpers/sensors>
|
+<helpers/sensors>
|
||||||
+<helpers/ui/NullDisplayDriver.cpp>
|
+<helpers/ui/NullDisplayDriver.cpp>
|
||||||
+<../variants/ikoka_nano_nrf>
|
+<../variants/ikoka_nano_nrf>
|
||||||
|
|
||||||
[ikoka_nano_nrf_e22_30dbm]
|
[ikoka_nano_nrf_e22_30dbm]
|
||||||
extends = ikoka_nano_nrf
|
extends = ikoka_nano_nrf_baseboard
|
||||||
; limit txpower to 20dBm on E22-900M30S. Anything higher will
|
; limit txpower to 20dBm on E22-900M30S. Anything higher will
|
||||||
; cause distortion in the PA output. 20dBm in -> 30dBm out
|
; cause distortion in the PA output. 20dBm in -> 30dBm out
|
||||||
build_flags =
|
build_flags =
|
||||||
${ikoka_nano_nrf.build_flags}
|
${ikoka_nano_nrf_baseboard.build_flags}
|
||||||
-D MANUFACTURER_STRING='"Ikoka Nano-E22-30dBm (Xiao_nrf52)"'
|
-D MANUFACTURER_STRING='"Ikoka Nano-E22-30dBm (Xiao_nrf52)"'
|
||||||
-D LORA_TX_POWER=20
|
-D LORA_TX_POWER=20
|
||||||
build_src_filter = ${ikoka_nano_nrf.build_src_filter}
|
build_src_filter = ${nrf52840_xiao.build_src_filter}
|
||||||
+<helpers/*.cpp>
|
+<helpers/*.cpp>
|
||||||
+<helpers/sensors>
|
+<helpers/sensors>
|
||||||
+<helpers/ui/NullDisplayDriver.cpp>
|
+<helpers/ui/NullDisplayDriver.cpp>
|
||||||
+<../variants/ikoka_nano_nrf>
|
+<../variants/ikoka_nano_nrf>
|
||||||
|
|
||||||
[ikoka_nano_nrf_e22_33dbm]
|
[ikoka_nano_nrf_e22_33dbm]
|
||||||
extends = ikoka_nano_nrf
|
extends = ikoka_nano_nrf_baseboard
|
||||||
; limit txpower to 9dBm on E22-900M33S to avoid hardware damage
|
; limit txpower to 9dBm on E22-900M33S to avoid hardware damage
|
||||||
; to the rf amplifier frontend. 9dBm in -> 33dBm out
|
; to the rf amplifier frontend. 9dBm in -> 33dBm out
|
||||||
build_flags =
|
build_flags =
|
||||||
${ikoka_nano_nrf.build_flags}
|
${ikoka_nano_nrf_baseboard.build_flags}
|
||||||
-D MANUFACTURER_STRING='"Ikoka Nano-E22-33dBm (Xiao_nrf52)"'
|
-D MANUFACTURER_STRING='"Ikoka Nano-E22-33dBm (Xiao_nrf52)"'
|
||||||
-D LORA_TX_POWER=9
|
-D LORA_TX_POWER=9
|
||||||
build_src_filter = ${ikoka_nano_nrf.build_src_filter}
|
build_src_filter = ${nrf52840_xiao.build_src_filter}
|
||||||
+<helpers/*.cpp>
|
+<helpers/*.cpp>
|
||||||
+<helpers/sensors>
|
+<helpers/sensors>
|
||||||
+<helpers/ui/NullDisplayDriver.cpp>
|
+<helpers/ui/NullDisplayDriver.cpp>
|
||||||
+<../variants/ikoka_nano_nrf>
|
+<../variants/ikoka_nano_nrf>
|
||||||
|
|
||||||
|
;;; abstracted firmware roles
|
||||||
|
|
||||||
[ikoka_nano_nrf_companion_radio_ble]
|
[ikoka_nano_nrf_companion_radio_ble]
|
||||||
extends = ikoka_nano_nrf
|
extends = ikoka_nano_nrf_baseboard
|
||||||
board_build.ldscript = boards/nrf52840_s140_v7_extrafs.ld
|
board_build.ldscript = boards/nrf52840_s140_v7_extrafs.ld
|
||||||
board_upload.maximum_size = 708608
|
board_upload.maximum_size = 708608
|
||||||
build_flags =
|
build_flags =
|
||||||
${ikoka_nano_nrf.build_flags}
|
${ikoka_nano_nrf_baseboard.build_flags}
|
||||||
-D MAX_CONTACTS=350
|
-D MAX_CONTACTS=350
|
||||||
-D MAX_GROUP_CHANNELS=40
|
-D MAX_GROUP_CHANNELS=40
|
||||||
-D BLE_PIN_CODE=123456
|
-D BLE_PIN_CODE=123456
|
||||||
-D OFFLINE_QUEUE_SIZE=256
|
-D OFFLINE_QUEUE_SIZE=256
|
||||||
-I examples/companion_radio/ui-new
|
-I examples/companion_radio/ui-new
|
||||||
-D QSPIFLASH=1
|
|
||||||
; -D BLE_DEBUG_LOGGING=1
|
; -D BLE_DEBUG_LOGGING=1
|
||||||
; -D MESH_PACKET_LOGGING=1
|
; -D MESH_PACKET_LOGGING=1
|
||||||
; -D MESH_DEBUG=1
|
; -D MESH_DEBUG=1
|
||||||
build_src_filter = ${ikoka_nano_nrf.build_src_filter}
|
build_src_filter = ${ikoka_nano_nrf_baseboard.build_src_filter}
|
||||||
+<helpers/nrf52/SerialBLEInterface.cpp>
|
+<helpers/nrf52/SerialBLEInterface.cpp>
|
||||||
+<../examples/companion_radio/*.cpp>
|
+<../examples/companion_radio/*.cpp>
|
||||||
+<../examples/companion_radio/ui-new/*.cpp>
|
+<../examples/companion_radio/ui-new/*.cpp>
|
||||||
lib_deps =
|
lib_deps =
|
||||||
${ikoka_nano_nrf.lib_deps}
|
${ikoka_nano_nrf_baseboard.lib_deps}
|
||||||
densaugeo/base64 @ ~1.4.0
|
densaugeo/base64 @ ~1.4.0
|
||||||
|
|
||||||
[ikoka_nano_nrf_companion_radio_usb]
|
[ikoka_nano_nrf_companion_radio_usb]
|
||||||
extends = ikoka_nano_nrf
|
extends = ikoka_nano_nrf_baseboard
|
||||||
board_build.ldscript = boards/nrf52840_s140_v7_extrafs.ld
|
board_build.ldscript = boards/nrf52840_s140_v7_extrafs.ld
|
||||||
board_upload.maximum_size = 708608
|
board_upload.maximum_size = 708608
|
||||||
build_flags =
|
build_flags =
|
||||||
${ikoka_nano_nrf.build_flags}
|
${ikoka_nano_nrf_baseboard.build_flags}
|
||||||
-D MAX_CONTACTS=350
|
-D MAX_CONTACTS=350
|
||||||
-D MAX_GROUP_CHANNELS=40
|
-D MAX_GROUP_CHANNELS=40
|
||||||
-I examples/companion_radio/ui-new
|
-I examples/companion_radio/ui-new
|
||||||
-D QSPIFLASH=1
|
|
||||||
; -D MESH_PACKET_LOGGING=1
|
; -D MESH_PACKET_LOGGING=1
|
||||||
; -D MESH_DEBUG=1
|
; -D MESH_DEBUG=1
|
||||||
build_src_filter = ${ikoka_nano_nrf.build_src_filter}
|
build_src_filter = ${ikoka_nano_nrf_baseboard.build_src_filter}
|
||||||
+<helpers/nrf52/SerialBLEInterface.cpp>
|
+<helpers/nrf52/SerialBLEInterface.cpp>
|
||||||
+<../examples/companion_radio/*.cpp>
|
+<../examples/companion_radio/*.cpp>
|
||||||
+<../examples/companion_radio/ui-new/*.cpp>
|
+<../examples/companion_radio/ui-new/*.cpp>
|
||||||
lib_deps =
|
lib_deps =
|
||||||
${ikoka_nano_nrf.lib_deps}
|
${ikoka_nano_nrf_baseboard.lib_deps}
|
||||||
densaugeo/base64 @ ~1.4.0
|
densaugeo/base64 @ ~1.4.0
|
||||||
|
|
||||||
[ikoka_nano_nrf_repeater]
|
[ikoka_nano_nrf_repeater]
|
||||||
extends = ikoka_nano_nrf
|
extends = ikoka_nano_nrf_baseboard
|
||||||
build_flags =
|
build_flags =
|
||||||
${ikoka_nano_nrf.build_flags}
|
${ikoka_nano_nrf_baseboard.build_flags}
|
||||||
-D ADVERT_NAME='"Ikoka Nano Repeater"'
|
-D ADVERT_NAME='"Ikoka Nano Repeater"'
|
||||||
-D ADVERT_LAT=0.0
|
-D ADVERT_LAT=0.0
|
||||||
-D ADVERT_LON=0.0
|
-D ADVERT_LON=0.0
|
||||||
@@ -126,23 +153,26 @@ build_flags =
|
|||||||
-D MAX_NEIGHBOURS=50
|
-D MAX_NEIGHBOURS=50
|
||||||
; -D MESH_PACKET_LOGGING=1
|
; -D MESH_PACKET_LOGGING=1
|
||||||
; -D MESH_DEBUG=1
|
; -D MESH_DEBUG=1
|
||||||
build_src_filter = ${ikoka_nano_nrf.build_src_filter}
|
build_src_filter = ${ikoka_nano_nrf_baseboard.build_src_filter}
|
||||||
+<../examples/simple_repeater/*.cpp>
|
+<../examples/simple_repeater/*.cpp>
|
||||||
|
|
||||||
[ikoka_nano_nrf_room_server]
|
[ikoka_nano_nrf_room_server]
|
||||||
extends = ikoka_nano_nrf
|
extends = ikoka_nano_nrf_baseboard
|
||||||
build_flags =
|
build_flags =
|
||||||
${ikoka_nano_nrf.build_flags}
|
${ikoka_nano_nrf_baseboard.build_flags}
|
||||||
-D ADVERT_NAME='"Ikoka Nano Room"'
|
-D ADVERT_NAME='"Ikoka Nano Room"'
|
||||||
-D ADVERT_LAT=0.0
|
-D ADVERT_LAT=0.0
|
||||||
-D ADVERT_LON=0.0
|
-D ADVERT_LON=0.0
|
||||||
-D ADMIN_PASSWORD='"password"'
|
-D ADMIN_PASSWORD='"password"'
|
||||||
; -D MESH_PACKET_LOGGING=1
|
; -D MESH_PACKET_LOGGING=1
|
||||||
; -D MESH_DEBUG=1
|
; -D MESH_DEBUG=1
|
||||||
build_src_filter = ${ikoka_nano_nrf.build_src_filter}
|
build_src_filter = ${ikoka_nano_nrf_baseboard.build_src_filter}
|
||||||
+<../examples/simple_room_server/*.cpp>
|
+<../examples/simple_room_server/*.cpp>
|
||||||
|
|
||||||
|
;;; hardware + firmware variants
|
||||||
|
|
||||||
;;; 22dBm EBYTE E22-900M22 variants
|
;;; 22dBm EBYTE E22-900M22 variants
|
||||||
|
|
||||||
[env:ikoka_nano_nrf_22dbm_companion_radio_usb]
|
[env:ikoka_nano_nrf_22dbm_companion_radio_usb]
|
||||||
extends =
|
extends =
|
||||||
ikoka_nano_nrf_e22_22dbm
|
ikoka_nano_nrf_e22_22dbm
|
||||||
@@ -189,6 +219,7 @@ build_src_filter =
|
|||||||
|
|
||||||
|
|
||||||
;;; 30dBm EBYTE E22-900M30 variants
|
;;; 30dBm EBYTE E22-900M30 variants
|
||||||
|
|
||||||
[env:ikoka_nano_nrf_30dbm_companion_radio_usb]
|
[env:ikoka_nano_nrf_30dbm_companion_radio_usb]
|
||||||
extends =
|
extends =
|
||||||
ikoka_nano_nrf_e22_30dbm
|
ikoka_nano_nrf_e22_30dbm
|
||||||
@@ -235,6 +266,7 @@ build_src_filter =
|
|||||||
|
|
||||||
|
|
||||||
;;; 33dBm EBYTE E22-900M33 variants
|
;;; 33dBm EBYTE E22-900M33 variants
|
||||||
|
|
||||||
[env:ikoka_nano_nrf_33dbm_companion_radio_usb]
|
[env:ikoka_nano_nrf_33dbm_companion_radio_usb]
|
||||||
extends =
|
extends =
|
||||||
ikoka_nano_nrf_e22_33dbm
|
ikoka_nano_nrf_e22_33dbm
|
||||||
|
|||||||
@@ -1,15 +1,34 @@
|
|||||||
[ikoka_stick_nrf]
|
[nrf52840_xiao]
|
||||||
extends = nrf52_base
|
extends = nrf52_base
|
||||||
|
platform_packages =
|
||||||
|
toolchain-gccarmnoneeabi@~1.100301.0
|
||||||
|
framework-arduinoadafruitnrf52
|
||||||
board = seeed-xiao-afruitnrf52-nrf52840
|
board = seeed-xiao-afruitnrf52-nrf52840
|
||||||
board_build.ldscript = boards/nrf52840_s140_v7.ld
|
board_build.ldscript = boards/nrf52840_s140_v7.ld
|
||||||
build_flags = ${nrf52_base.build_flags}
|
build_flags = ${nrf52_base.build_flags}
|
||||||
${sensor_base.build_flags}
|
|
||||||
-D NRF52_PLATFORM -D XIAO_NRF52
|
-D NRF52_PLATFORM -D XIAO_NRF52
|
||||||
-I lib/nrf52/s140_nrf52_7.3.0_API/include
|
-I lib/nrf52/s140_nrf52_7.3.0_API/include
|
||||||
-I lib/nrf52/s140_nrf52_7.3.0_API/include/nrf52
|
-I lib/nrf52/s140_nrf52_7.3.0_API/include/nrf52
|
||||||
|
lib_ignore =
|
||||||
|
BluetoothOTA
|
||||||
|
lvgl
|
||||||
|
lib5b4
|
||||||
|
lib_deps =
|
||||||
|
${nrf52_base.lib_deps}
|
||||||
|
rweather/Crypto @ ^0.4.0
|
||||||
|
adafruit/Adafruit INA3221 Library @ ^1.0.1
|
||||||
|
adafruit/Adafruit INA219 @ ^1.2.3
|
||||||
|
adafruit/Adafruit AHTX0 @ ^2.0.5
|
||||||
|
adafruit/Adafruit BME280 Library @ ^2.3.0
|
||||||
|
adafruit/Adafruit SSD1306 @ ^2.5.13
|
||||||
|
|
||||||
|
[ikoka_stick_nrf_baseboard]
|
||||||
|
extends = nrf52840_xiao
|
||||||
|
;board_build.ldscript = boards/nrf52840_s140_v7.ld
|
||||||
|
build_flags = ${nrf52840_xiao.build_flags}
|
||||||
|
-D P_LORA_TX_LED=11
|
||||||
-I variants/ikoka_stick_nrf
|
-I variants/ikoka_stick_nrf
|
||||||
-I src/helpers/nrf52
|
-I src/helpers/nrf52
|
||||||
-D P_LORA_TX_LED=11
|
|
||||||
-D DISPLAY_CLASS=SSD1306Display
|
-D DISPLAY_CLASS=SSD1306Display
|
||||||
-D DISPLAY_ROTATION=2
|
-D DISPLAY_ROTATION=2
|
||||||
-D RADIO_CLASS=CustomSX1262
|
-D RADIO_CLASS=CustomSX1262
|
||||||
@@ -27,18 +46,24 @@ build_flags = ${nrf52_base.build_flags}
|
|||||||
-D PIN_USER_BTN=0
|
-D PIN_USER_BTN=0
|
||||||
-D PIN_WIRE_SCL=7
|
-D PIN_WIRE_SCL=7
|
||||||
-D PIN_WIRE_SDA=6
|
-D PIN_WIRE_SDA=6
|
||||||
-UENV_INCLUDE_GPS
|
-D ENV_INCLUDE_AHTX0=1
|
||||||
lib_deps = ${nrf52_base.lib_deps}
|
-D ENV_INCLUDE_BME280=1
|
||||||
${sensor_base.lib_deps}
|
-D ENV_INCLUDE_INA3221=1
|
||||||
|
-D ENV_INCLUDE_INA219=1
|
||||||
|
debug_tool = jlink
|
||||||
|
upload_protocol = nrfutil
|
||||||
|
|
||||||
|
|
||||||
|
;;; abstracted hardware variants
|
||||||
|
|
||||||
[ikoka_stick_nrf_e22_22dbm]
|
[ikoka_stick_nrf_e22_22dbm]
|
||||||
extends = ikoka_stick_nrf
|
extends = ikoka_stick_nrf_baseboard
|
||||||
; No PA in this model, full 22dBm
|
; No PA in this model, full 22dBm
|
||||||
build_flags =
|
build_flags =
|
||||||
${ikoka_stick_nrf.build_flags}
|
${ikoka_stick_nrf_baseboard.build_flags}
|
||||||
-D MANUFACTURER_STRING='"Ikoka Stick-E22-22dBm (Xiao_nrf52)"'
|
-D MANUFACTURER_STRING='"Ikoka Stick-E22-22dBm (Xiao_nrf52)"'
|
||||||
-D LORA_TX_POWER=22
|
-D LORA_TX_POWER=22
|
||||||
build_src_filter = ${ikoka_stick_nrf.build_src_filter}
|
build_src_filter = ${nrf52840_xiao.build_src_filter}
|
||||||
+<helpers/*.cpp>
|
+<helpers/*.cpp>
|
||||||
+<helpers/sensors>
|
+<helpers/sensors>
|
||||||
+<helpers/ui/MomentaryButton.cpp>
|
+<helpers/ui/MomentaryButton.cpp>
|
||||||
@@ -46,14 +71,14 @@ build_src_filter = ${ikoka_stick_nrf.build_src_filter}
|
|||||||
+<../variants/ikoka_stick_nrf>
|
+<../variants/ikoka_stick_nrf>
|
||||||
|
|
||||||
[ikoka_stick_nrf_e22_30dbm]
|
[ikoka_stick_nrf_e22_30dbm]
|
||||||
extends = ikoka_stick_nrf
|
extends = ikoka_stick_nrf_baseboard
|
||||||
; limit txpower to 20dBm on E22-900M30S. Anything higher will
|
; limit txpower to 20dBm on E22-900M30S. Anything higher will
|
||||||
; cause distortion in the PA output. 20dBm in -> 30dBm out
|
; cause distortion in the PA output. 20dBm in -> 30dBm out
|
||||||
build_flags =
|
build_flags =
|
||||||
${ikoka_stick_nrf.build_flags}
|
${ikoka_stick_nrf_baseboard.build_flags}
|
||||||
-D MANUFACTURER_STRING='"Ikoka Stick-E22-30dBm (Xiao_nrf52)"'
|
-D MANUFACTURER_STRING='"Ikoka Stick-E22-30dBm (Xiao_nrf52)"'
|
||||||
-D LORA_TX_POWER=20
|
-D LORA_TX_POWER=20
|
||||||
build_src_filter = ${ikoka_stick_nrf.build_src_filter}
|
build_src_filter = ${nrf52840_xiao.build_src_filter}
|
||||||
+<helpers/*.cpp>
|
+<helpers/*.cpp>
|
||||||
+<helpers/sensors>
|
+<helpers/sensors>
|
||||||
+<helpers/ui/MomentaryButton.cpp>
|
+<helpers/ui/MomentaryButton.cpp>
|
||||||
@@ -61,14 +86,14 @@ build_src_filter = ${ikoka_stick_nrf.build_src_filter}
|
|||||||
+<../variants/ikoka_stick_nrf>
|
+<../variants/ikoka_stick_nrf>
|
||||||
|
|
||||||
[ikoka_stick_nrf_e22_33dbm]
|
[ikoka_stick_nrf_e22_33dbm]
|
||||||
extends = ikoka_stick_nrf
|
extends = ikoka_stick_nrf_baseboard
|
||||||
; limit txpower to 9dBm on E22-900M33S to avoid hardware damage
|
; limit txpower to 9dBm on E22-900M33S to avoid hardware damage
|
||||||
; to the rf amplifier frontend. 9dBm in -> 33dBm out
|
; to the rf amplifier frontend. 9dBm in -> 33dBm out
|
||||||
build_flags =
|
build_flags =
|
||||||
${ikoka_stick_nrf.build_flags}
|
${ikoka_stick_nrf_baseboard.build_flags}
|
||||||
-D MANUFACTURER_STRING='"Ikoka Stick-E22-33dBm (Xiao_nrf52)"'
|
-D MANUFACTURER_STRING='"Ikoka Stick-E22-33dBm (Xiao_nrf52)"'
|
||||||
-D LORA_TX_POWER=9
|
-D LORA_TX_POWER=9
|
||||||
build_src_filter = ${ikoka_stick_nrf.build_src_filter}
|
build_src_filter = ${nrf52840_xiao.build_src_filter}
|
||||||
+<helpers/*.cpp>
|
+<helpers/*.cpp>
|
||||||
+<helpers/sensors>
|
+<helpers/sensors>
|
||||||
+<helpers/ui/MomentaryButton.cpp>
|
+<helpers/ui/MomentaryButton.cpp>
|
||||||
@@ -78,52 +103,50 @@ build_src_filter = ${ikoka_stick_nrf.build_src_filter}
|
|||||||
;;; abstracted firmware roles
|
;;; abstracted firmware roles
|
||||||
|
|
||||||
[ikoka_stick_nrf_companion_radio_ble]
|
[ikoka_stick_nrf_companion_radio_ble]
|
||||||
extends = ikoka_stick_nrf
|
extends = ikoka_stick_nrf_baseboard
|
||||||
board_build.ldscript = boards/nrf52840_s140_v7_extrafs.ld
|
board_build.ldscript = boards/nrf52840_s140_v7_extrafs.ld
|
||||||
board_upload.maximum_size = 708608
|
board_upload.maximum_size = 708608
|
||||||
build_flags =
|
build_flags =
|
||||||
${ikoka_stick_nrf.build_flags}
|
${ikoka_stick_nrf_baseboard.build_flags}
|
||||||
-D MAX_CONTACTS=350
|
-D MAX_CONTACTS=350
|
||||||
-D MAX_GROUP_CHANNELS=40
|
-D MAX_GROUP_CHANNELS=40
|
||||||
-D BLE_PIN_CODE=123456
|
-D BLE_PIN_CODE=123456
|
||||||
-D OFFLINE_QUEUE_SIZE=256
|
-D OFFLINE_QUEUE_SIZE=256
|
||||||
-I examples/companion_radio/ui-new
|
-I examples/companion_radio/ui-new
|
||||||
-D QSPIFLASH=1
|
|
||||||
; -D BLE_DEBUG_LOGGING=1
|
; -D BLE_DEBUG_LOGGING=1
|
||||||
; -D MESH_PACKET_LOGGING=1
|
; -D MESH_PACKET_LOGGING=1
|
||||||
; -D MESH_DEBUG=1
|
; -D MESH_DEBUG=1
|
||||||
build_src_filter = ${ikoka_stick_nrf.build_src_filter}
|
build_src_filter = ${ikoka_stick_nrf_baseboard.build_src_filter}
|
||||||
+<helpers/nrf52/SerialBLEInterface.cpp>
|
+<helpers/nrf52/SerialBLEInterface.cpp>
|
||||||
+<../examples/companion_radio/*.cpp>
|
+<../examples/companion_radio/*.cpp>
|
||||||
+<../examples/companion_radio/ui-new/*.cpp>
|
+<../examples/companion_radio/ui-new/*.cpp>
|
||||||
lib_deps =
|
lib_deps =
|
||||||
${ikoka_stick_nrf.lib_deps}
|
${ikoka_stick_nrf_baseboard.lib_deps}
|
||||||
densaugeo/base64 @ ~1.4.0
|
densaugeo/base64 @ ~1.4.0
|
||||||
|
|
||||||
[ikoka_stick_nrf_companion_radio_usb]
|
[ikoka_stick_nrf_companion_radio_usb]
|
||||||
extends = ikoka_stick_nrf
|
extends = ikoka_stick_nrf_baseboard
|
||||||
board_build.ldscript = boards/nrf52840_s140_v7_extrafs.ld
|
board_build.ldscript = boards/nrf52840_s140_v7_extrafs.ld
|
||||||
board_upload.maximum_size = 708608
|
board_upload.maximum_size = 708608
|
||||||
build_flags =
|
build_flags =
|
||||||
${ikoka_stick_nrf.build_flags}
|
${ikoka_stick_nrf_baseboard.build_flags}
|
||||||
-D MAX_CONTACTS=350
|
-D MAX_CONTACTS=350
|
||||||
-D MAX_GROUP_CHANNELS=40
|
-D MAX_GROUP_CHANNELS=40
|
||||||
-I examples/companion_radio/ui-new
|
-I examples/companion_radio/ui-new
|
||||||
-D QSPIFLASH=1
|
|
||||||
; -D MESH_PACKET_LOGGING=1
|
; -D MESH_PACKET_LOGGING=1
|
||||||
; -D MESH_DEBUG=1
|
; -D MESH_DEBUG=1
|
||||||
build_src_filter = ${ikoka_stick_nrf.build_src_filter}
|
build_src_filter = ${ikoka_stick_nrf_baseboard.build_src_filter}
|
||||||
+<helpers/nrf52/SerialBLEInterface.cpp>
|
+<helpers/nrf52/SerialBLEInterface.cpp>
|
||||||
+<../examples/companion_radio/*.cpp>
|
+<../examples/companion_radio/*.cpp>
|
||||||
+<../examples/companion_radio/ui-new/*.cpp>
|
+<../examples/companion_radio/ui-new/*.cpp>
|
||||||
lib_deps =
|
lib_deps =
|
||||||
${ikoka_stick_nrf.lib_deps}
|
${ikoka_stick_nrf_baseboard.lib_deps}
|
||||||
densaugeo/base64 @ ~1.4.0
|
densaugeo/base64 @ ~1.4.0
|
||||||
|
|
||||||
[ikoka_stick_nrf_repeater]
|
[ikoka_stick_nrf_repeater]
|
||||||
extends = ikoka_stick_nrf
|
extends = ikoka_stick_nrf_baseboard
|
||||||
build_flags =
|
build_flags =
|
||||||
${ikoka_stick_nrf.build_flags}
|
${ikoka_stick_nrf_baseboard.build_flags}
|
||||||
-D ADVERT_NAME='"Ikoka Stick Repeater"'
|
-D ADVERT_NAME='"Ikoka Stick Repeater"'
|
||||||
-D ADVERT_LAT=0.0
|
-D ADVERT_LAT=0.0
|
||||||
-D ADVERT_LON=0.0
|
-D ADVERT_LON=0.0
|
||||||
@@ -131,21 +154,21 @@ build_flags =
|
|||||||
-D MAX_NEIGHBOURS=50
|
-D MAX_NEIGHBOURS=50
|
||||||
; -D MESH_PACKET_LOGGING=1
|
; -D MESH_PACKET_LOGGING=1
|
||||||
; -D MESH_DEBUG=1
|
; -D MESH_DEBUG=1
|
||||||
build_src_filter = ${ikoka_stick_nrf.build_src_filter}
|
build_src_filter = ${ikoka_stick_nrf_baseboard.build_src_filter}
|
||||||
+<helpers/ui/SSD1306Display.cpp>
|
+<helpers/ui/SSD1306Display.cpp>
|
||||||
+<../examples/simple_repeater/*.cpp>
|
+<../examples/simple_repeater/*.cpp>
|
||||||
|
|
||||||
[ikoka_stick_nrf_room_server]
|
[ikoka_stick_nrf_room_server]
|
||||||
extends = ikoka_stick_nrf
|
extends = ikoka_stick_nrf_baseboard
|
||||||
build_flags =
|
build_flags =
|
||||||
${ikoka_stick_nrf.build_flags}
|
${ikoka_stick_nrf_baseboard.build_flags}
|
||||||
-D ADVERT_NAME='"Ikoka Stick Room"'
|
-D ADVERT_NAME='"Ikoka Stick Room"'
|
||||||
-D ADVERT_LAT=0.0
|
-D ADVERT_LAT=0.0
|
||||||
-D ADVERT_LON=0.0
|
-D ADVERT_LON=0.0
|
||||||
-D ADMIN_PASSWORD='"password"'
|
-D ADMIN_PASSWORD='"password"'
|
||||||
; -D MESH_PACKET_LOGGING=1
|
; -D MESH_PACKET_LOGGING=1
|
||||||
; -D MESH_DEBUG=1
|
; -D MESH_DEBUG=1
|
||||||
build_src_filter = ${ikoka_stick_nrf.build_src_filter}
|
build_src_filter = ${ikoka_stick_nrf_baseboard.build_src_filter}
|
||||||
+<../examples/simple_room_server/*.cpp>
|
+<../examples/simple_room_server/*.cpp>
|
||||||
|
|
||||||
;;; hardware + firmware variants
|
;;; hardware + firmware variants
|
||||||
|
|||||||
@@ -138,6 +138,8 @@ build_flags =
|
|||||||
-D DISPLAY_CLASS=SSD1306Display
|
-D DISPLAY_CLASS=SSD1306Display
|
||||||
-D MAX_CONTACTS=350
|
-D MAX_CONTACTS=350
|
||||||
-D MAX_GROUP_CHANNELS=40
|
-D MAX_GROUP_CHANNELS=40
|
||||||
|
-D MESH_PACKET_LOGGING=1
|
||||||
|
-D MESH_DEBUG=1
|
||||||
build_src_filter = ${LilyGo_T3S3_sx1276.build_src_filter}
|
build_src_filter = ${LilyGo_T3S3_sx1276.build_src_filter}
|
||||||
+<helpers/ui/SSD1306Display.cpp>
|
+<helpers/ui/SSD1306Display.cpp>
|
||||||
+<helpers/ui/MomentaryButton.cpp>
|
+<helpers/ui/MomentaryButton.cpp>
|
||||||
|
|||||||
Reference in New Issue
Block a user