From f58a34f5f4c201db63f3da9ce58d5b0f69c0fd6f Mon Sep 17 00:00:00 2001 From: hank Date: Thu, 29 May 2025 13:06:24 -0700 Subject: [PATCH 01/19] Refactored MyMesh, advert on doublepress Pulled the class out of main.cpp, made a header to go along with it, externed globals in headers to make them accessible to button code. Added button code to send an advert on double press. Refactored ini files to prevent linker errors. --- examples/companion_radio/MyMesh.cpp | 1819 ++++++++++++++++++++++++ examples/companion_radio/MyMesh.h | 283 ++++ examples/companion_radio/UITask.cpp | 11 +- examples/companion_radio/UITask.h | 4 +- examples/companion_radio/main.cpp | 1588 +-------------------- variants/generic_espnow/platformio.ini | 2 +- variants/promicro/platformio.ini | 4 +- variants/t114/platformio.ini | 4 +- variants/xiao_nrf52/platformio.ini | 4 +- variants/xiao_s3_wio/platformio.ini | 2 +- 10 files changed, 2135 insertions(+), 1586 deletions(-) create mode 100644 examples/companion_radio/MyMesh.cpp create mode 100644 examples/companion_radio/MyMesh.h diff --git a/examples/companion_radio/MyMesh.cpp b/examples/companion_radio/MyMesh.cpp new file mode 100644 index 000000000..6e9688a53 --- /dev/null +++ b/examples/companion_radio/MyMesh.cpp @@ -0,0 +1,1819 @@ +#include // needed for PlatformIO +#include +#include "MyMesh.h" + +#ifdef DISPLAY_CLASS + #include "UITask.h" +#endif + +void MyMesh::loadMainIdentity() +{ + if (!_identity_store->load("_main", self_id)) + { + self_id = radio_new_identity(); // create new random identity + int count = 0; + while (count < 10 && (self_id.pub_key[0] == 0x00 || self_id.pub_key[0] == 0xFF)) + { // reserved id hashes + self_id = radio_new_identity(); + count++; + } + saveMainIdentity(self_id); + } +} + +bool MyMesh::saveMainIdentity(const mesh::LocalIdentity &identity) +{ + return _identity_store->save("_main", identity); +} + +void MyMesh::loadContacts() +{ + if (_fs->exists("/contacts3")) + { +#if defined(RP2040_PLATFORM) + File file = _fs->open("/contacts3", "r"); +#else + File file = _fs->open("/contacts3"); +#endif + if (file) + { + bool full = false; + while (!full) + { + ContactInfo c; + uint8_t pub_key[32]; + uint8_t unused; + + bool success = (file.read(pub_key, 32) == 32); + success = success && (file.read((uint8_t *)&c.name, 32) == 32); + success = success && (file.read(&c.type, 1) == 1); + success = success && (file.read(&c.flags, 1) == 1); + success = success && (file.read(&unused, 1) == 1); + success = success && (file.read((uint8_t *)&c.sync_since, 4) == 4); // was 'reserved' + success = success && (file.read((uint8_t *)&c.out_path_len, 1) == 1); + success = success && (file.read((uint8_t *)&c.last_advert_timestamp, 4) == 4); + success = success && (file.read(c.out_path, 64) == 64); + success = success && (file.read((uint8_t *)&c.lastmod, 4) == 4); + success = success && (file.read((uint8_t *)&c.gps_lat, 4) == 4); + success = success && (file.read((uint8_t *)&c.gps_lon, 4) == 4); + + if (!success) + break; // EOF + + c.id = mesh::Identity(pub_key); + if (!addContact(c)) + full = true; + } + file.close(); + } + } +} + +void MyMesh::saveContacts() +{ +#if defined(NRF52_PLATFORM) || defined(STM32_PLATFORM) + _fs->remove("/contacts3"); + File file = _fs->open("/contacts3", FILE_O_WRITE); +#elif defined(RP2040_PLATFORM) + File file = _fs->open("/contacts3", "w"); +#else + File file = _fs->open("/contacts3", "w", true); +#endif + if (file) + { + ContactsIterator iter; + ContactInfo c; + uint8_t unused = 0; + + while (iter.hasNext(this, c)) + { + bool success = (file.write(c.id.pub_key, 32) == 32); + success = success && (file.write((uint8_t *)&c.name, 32) == 32); + success = success && (file.write(&c.type, 1) == 1); + success = success && (file.write(&c.flags, 1) == 1); + success = success && (file.write(&unused, 1) == 1); + success = success && (file.write((uint8_t *)&c.sync_since, 4) == 4); + success = success && (file.write((uint8_t *)&c.out_path_len, 1) == 1); + success = success && (file.write((uint8_t *)&c.last_advert_timestamp, 4) == 4); + success = success && (file.write(c.out_path, 64) == 64); + success = success && (file.write((uint8_t *)&c.lastmod, 4) == 4); + success = success && (file.write((uint8_t *)&c.gps_lat, 4) == 4); + success = success && (file.write((uint8_t *)&c.gps_lon, 4) == 4); + + if (!success) + break; // write failed + } + file.close(); + } +} + +void MyMesh::loadChannels() +{ + if (_fs->exists("/channels2")) + { +#if defined(RP2040_PLATFORM) + File file = _fs->open("/channels2", "r"); +#else + File file = _fs->open("/channels2"); +#endif + if (file) + { + bool full = false; + uint8_t channel_idx = 0; + while (!full) + { + ChannelDetails ch; + uint8_t unused[4]; + + bool success = (file.read(unused, 4) == 4); + success = success && (file.read((uint8_t *)ch.name, 32) == 32); + success = success && (file.read((uint8_t *)ch.channel.secret, 32) == 32); + + if (!success) + break; // EOF + + if (setChannel(channel_idx, ch)) + { + channel_idx++; + } + else + { + full = true; + } + } + file.close(); + } + } +} + +void MyMesh::saveChannels() +{ +#if defined(NRF52_PLATFORM) || defined(STM32_PLATFORM) + _fs->remove("/channels2"); + File file = _fs->open("/channels2", FILE_O_WRITE); +#elif defined(RP2040_PLATFORM) + File file = _fs->open("/channels2", "w"); +#else + File file = _fs->open("/channels2", "w", true); +#endif + if (file) + { + uint8_t channel_idx = 0; + ChannelDetails ch; + uint8_t unused[4]; + memset(unused, 0, 4); + + while (getChannel(channel_idx, ch)) + { + bool success = (file.write(unused, 4) == 4); + success = success && (file.write((uint8_t *)ch.name, 32) == 32); + success = success && (file.write((uint8_t *)ch.channel.secret, 32) == 32); + + if (!success) + break; // write failed + channel_idx++; + } + file.close(); + } +} + +int MyMesh::getBlobByKey(const uint8_t key[], int key_len, uint8_t dest_buf[]) +{ + char path[64]; + char fname[18]; + + if (key_len > 8) + key_len = 8; // just use first 8 bytes (prefix) + mesh::Utils::toHex(fname, key, key_len); + sprintf(path, "/bl/%s", fname); + + if (_fs->exists(path)) + { +#if defined(RP2040_PLATFORM) + File f = _fs->open(path, "r"); +#else + File f = _fs->open(path); +#endif + if (f) + { + int len = f.read(dest_buf, 255); // currently MAX 255 byte blob len supported!! + f.close(); + return len; + } + } + return 0; // not found +} + +bool MyMesh::putBlobByKey(const uint8_t key[], int key_len, const uint8_t src_buf[], int len) +{ + char path[64]; + char fname[18]; + + if (key_len > 8) + key_len = 8; // just use first 8 bytes (prefix) + mesh::Utils::toHex(fname, key, key_len); + sprintf(path, "/bl/%s", fname); + +#if defined(NRF52_PLATFORM) || defined(STM32_PLATFORM) + _fs->remove(path); + File f = _fs->open(path, FILE_O_WRITE); +#elif defined(RP2040_PLATFORM) + File f = _fs->open(path, "w"); +#else + File f = _fs->open(path, "w", true); +#endif + if (f) + { + int n = f.write(src_buf, len); + f.close(); + if (n == len) + return true; // success! + + _fs->remove(path); // blob was only partially written! + } + return false; // error +} + +void MyMesh::writeOKFrame() +{ + uint8_t buf[1]; + buf[0] = RESP_CODE_OK; + _serial->writeFrame(buf, 1); +} +void MyMesh::writeErrFrame(uint8_t err_code) +{ + uint8_t buf[2]; + buf[0] = RESP_CODE_ERR; + buf[1] = err_code; + _serial->writeFrame(buf, 2); +} + +void MyMesh::writeDisabledFrame() +{ + uint8_t buf[1]; + buf[0] = RESP_CODE_DISABLED; + _serial->writeFrame(buf, 1); +} + +void MyMesh::writeContactRespFrame(uint8_t code, const ContactInfo &contact) +{ + int i = 0; + out_frame[i++] = code; + memcpy(&out_frame[i], contact.id.pub_key, PUB_KEY_SIZE); + i += PUB_KEY_SIZE; + out_frame[i++] = contact.type; + out_frame[i++] = contact.flags; + out_frame[i++] = contact.out_path_len; + memcpy(&out_frame[i], contact.out_path, MAX_PATH_SIZE); + i += MAX_PATH_SIZE; + StrHelper::strzcpy((char *)&out_frame[i], contact.name, 32); + i += 32; + memcpy(&out_frame[i], &contact.last_advert_timestamp, 4); + i += 4; + memcpy(&out_frame[i], &contact.gps_lat, 4); + i += 4; + memcpy(&out_frame[i], &contact.gps_lon, 4); + i += 4; + memcpy(&out_frame[i], &contact.lastmod, 4); + i += 4; + _serial->writeFrame(out_frame, i); +} + +void MyMesh::updateContactFromFrame(ContactInfo &contact, const uint8_t *frame, int len) +{ + int i = 0; + uint8_t code = frame[i++]; // eg. CMD_ADD_UPDATE_CONTACT + memcpy(contact.id.pub_key, &frame[i], PUB_KEY_SIZE); + i += PUB_KEY_SIZE; + contact.type = frame[i++]; + contact.flags = frame[i++]; + contact.out_path_len = frame[i++]; + memcpy(contact.out_path, &frame[i], MAX_PATH_SIZE); + i += MAX_PATH_SIZE; + memcpy(contact.name, &frame[i], 32); + i += 32; + memcpy(&contact.last_advert_timestamp, &frame[i], 4); + i += 4; + if (i + 8 >= len) + { // optional fields + memcpy(&contact.gps_lat, &frame[i], 4); + i += 4; + memcpy(&contact.gps_lon, &frame[i], 4); + i += 4; + } +} + +void MyMesh::addToOfflineQueue(const uint8_t frame[], int len) +{ + if (offline_queue_len >= OFFLINE_QUEUE_SIZE) + { + MESH_DEBUG_PRINTLN("ERROR: offline_queue is full!"); + } + else + { + offline_queue[offline_queue_len].len = len; + memcpy(offline_queue[offline_queue_len].buf, frame, len); + offline_queue_len++; + } +} +int MyMesh::getFromOfflineQueue(uint8_t frame[]) +{ + if (offline_queue_len > 0) + { // check offline queue + size_t len = offline_queue[0].len; // take from top of queue + memcpy(frame, offline_queue[0].buf, len); + + offline_queue_len--; + for (int i = 0; i < offline_queue_len; i++) + { // delete top item from queue + offline_queue[i] = offline_queue[i + 1]; + } + return len; + } + return 0; // queue is empty +} + +float MyMesh::getAirtimeBudgetFactor() const +{ + return _prefs.airtime_factor; +} + +int MyMesh::getInterferenceThreshold() const +{ + return 14; // hard-coded for now +} + +int MyMesh::calcRxDelay(float score, uint32_t air_time) const +{ + if (_prefs.rx_delay_base <= 0.0f) + return 0; + return (int)((pow(_prefs.rx_delay_base, 0.85f - score) - 1.0) * air_time); +} + +void MyMesh::logRxRaw(float snr, float rssi, const uint8_t raw[], int len) +{ + if (_serial->isConnected() && len + 3 <= MAX_FRAME_SIZE) + { + int i = 0; + out_frame[i++] = PUSH_CODE_LOG_RX_DATA; + out_frame[i++] = (int8_t)(snr * 4); + out_frame[i++] = (int8_t)(rssi); + memcpy(&out_frame[i], raw, len); + i += len; + + _serial->writeFrame(out_frame, i); + } +} + +bool MyMesh::isAutoAddEnabled() const +{ + return (_prefs.manual_add_contacts & 1) == 0; +} + +void MyMesh::onDiscoveredContact(ContactInfo &contact, bool is_new) +{ + if (_serial->isConnected()) + { + if (!isAutoAddEnabled() && is_new) + { + writeContactRespFrame(PUSH_CODE_NEW_ADVERT, contact); + } + else + { + out_frame[0] = PUSH_CODE_ADVERT; + memcpy(&out_frame[1], contact.id.pub_key, PUB_KEY_SIZE); + _serial->writeFrame(out_frame, 1 + PUB_KEY_SIZE); + } + } + else + { +#ifdef DISPLAY_CLASS + ui_task.soundBuzzer(UIEventType::newContactMessage); +#endif + } + + dirty_contacts_expiry = futureMillis(LAZY_CONTACTS_WRITE_DELAY); +} + +void MyMesh::onContactPathUpdated(const ContactInfo &contact) +{ + out_frame[0] = PUSH_CODE_PATH_UPDATED; + memcpy(&out_frame[1], contact.id.pub_key, PUB_KEY_SIZE); + _serial->writeFrame(out_frame, 1 + PUB_KEY_SIZE); // NOTE: app may not be connected + + dirty_contacts_expiry = futureMillis(LAZY_CONTACTS_WRITE_DELAY); +} + +bool MyMesh::processAck(const uint8_t *data) +{ + // see if matches any in a table + for (int i = 0; i < EXPECTED_ACK_TABLE_SIZE; i++) + { + if (memcmp(data, &expected_ack_table[i].ack, 4) == 0) + { // got an ACK from recipient + out_frame[0] = PUSH_CODE_SEND_CONFIRMED; + memcpy(&out_frame[1], data, 4); + uint32_t trip_time = _ms->getMillis() - expected_ack_table[i].msg_sent; + memcpy(&out_frame[5], &trip_time, 4); + _serial->writeFrame(out_frame, 9); + + // NOTE: the same ACK can be received multiple times! + expected_ack_table[i].ack = 0; // clear expected hash, now that we have received ACK + return true; + } + } + return checkConnectionsAck(data); +} + +void MyMesh::queueMessage(const ContactInfo &from, uint8_t txt_type, mesh::Packet *pkt, uint32_t sender_timestamp, const uint8_t *extra, int extra_len, const char *text) +{ + int i = 0; + if (app_target_ver >= 3) + { + out_frame[i++] = RESP_CODE_CONTACT_MSG_RECV_V3; + out_frame[i++] = (int8_t)(pkt->getSNR() * 4); + out_frame[i++] = 0; // reserved1 + out_frame[i++] = 0; // reserved2 + } + else + { + out_frame[i++] = RESP_CODE_CONTACT_MSG_RECV; + } + memcpy(&out_frame[i], from.id.pub_key, 6); + i += 6; // just 6-byte prefix + uint8_t path_len = out_frame[i++] = pkt->isRouteFlood() ? pkt->path_len : 0xFF; + out_frame[i++] = txt_type; + memcpy(&out_frame[i], &sender_timestamp, 4); + i += 4; + if (extra_len > 0) + { + memcpy(&out_frame[i], extra, extra_len); + i += extra_len; + } + int tlen = strlen(text); // TODO: UTF-8 ?? + if (i + tlen > MAX_FRAME_SIZE) + { + tlen = MAX_FRAME_SIZE - i; + } + memcpy(&out_frame[i], text, tlen); + i += tlen; + addToOfflineQueue(out_frame, i); + + if (_serial->isConnected()) + { + uint8_t frame[1]; + frame[0] = PUSH_CODE_MSG_WAITING; // send push 'tickle' + _serial->writeFrame(frame, 1); + } + else + { +#ifdef DISPLAY_CLASS + ui_task.soundBuzzer(UIEventType::contactMessage); +#endif + } +#ifdef DISPLAY_CLASS + ui_task.newMsg(path_len, from.name, text, offline_queue_len); +#endif +} + +void MyMesh::onMessageRecv(const ContactInfo &from, mesh::Packet *pkt, uint32_t sender_timestamp, const char *text) +{ + markConnectionActive(from); // in case this is from a server, and we have a connection + queueMessage(from, TXT_TYPE_PLAIN, pkt, sender_timestamp, NULL, 0, text); +} + +void MyMesh::onCommandDataRecv(const ContactInfo &from, mesh::Packet *pkt, uint32_t sender_timestamp, const char *text) +{ + markConnectionActive(from); // in case this is from a server, and we have a connection + queueMessage(from, TXT_TYPE_CLI_DATA, pkt, sender_timestamp, NULL, 0, text); +} + +void MyMesh::onSignedMessageRecv(const ContactInfo &from, mesh::Packet *pkt, uint32_t sender_timestamp, const uint8_t *sender_prefix, const char *text) +{ + markConnectionActive(from); + // from.sync_since change needs to be persisted + dirty_contacts_expiry = futureMillis(LAZY_CONTACTS_WRITE_DELAY); + queueMessage(from, TXT_TYPE_SIGNED_PLAIN, pkt, sender_timestamp, sender_prefix, 4, text); +} + +void MyMesh::onChannelMessageRecv(const mesh::GroupChannel &channel, mesh::Packet *pkt, uint32_t timestamp, const char *text) +{ + int i = 0; + if (app_target_ver >= 3) + { + out_frame[i++] = RESP_CODE_CHANNEL_MSG_RECV_V3; + out_frame[i++] = (int8_t)(pkt->getSNR() * 4); + out_frame[i++] = 0; // reserved1 + out_frame[i++] = 0; // reserved2 + } + else + { + out_frame[i++] = RESP_CODE_CHANNEL_MSG_RECV; + } + + out_frame[i++] = findChannelIdx(channel); + uint8_t path_len = out_frame[i++] = pkt->isRouteFlood() ? pkt->path_len : 0xFF; + + out_frame[i++] = TXT_TYPE_PLAIN; + memcpy(&out_frame[i], ×tamp, 4); + i += 4; + int tlen = strlen(text); // TODO: UTF-8 ?? + if (i + tlen > MAX_FRAME_SIZE) + { + tlen = MAX_FRAME_SIZE - i; + } + memcpy(&out_frame[i], text, tlen); + i += tlen; + addToOfflineQueue(out_frame, i); + + if (_serial->isConnected()) + { + uint8_t frame[1]; + frame[0] = PUSH_CODE_MSG_WAITING; // send push 'tickle' + _serial->writeFrame(frame, 1); + } + else + { +#ifdef DISPLAY_CLASS + ui_task.soundBuzzer(UIEventType::channelMessage); +#endif + } +#ifdef DISPLAY_CLASS + ui_task.newMsg(path_len, "Public", text, offline_queue_len); +#endif +} + +uint8_t MyMesh::onContactRequest(const ContactInfo &contact, uint32_t sender_timestamp, const uint8_t *data, uint8_t len, uint8_t *reply) +{ + if (data[0] == REQ_TYPE_GET_TELEMETRY_DATA) + { + uint8_t permissions = 0; + uint8_t cp = contact.flags >> 1; // LSB used as 'favourite' bit (so only use upper bits) + + if (_prefs.telemetry_mode_base == TELEM_MODE_ALLOW_ALL) + { + permissions = TELEM_PERM_BASE; + } + else if (_prefs.telemetry_mode_base == TELEM_MODE_ALLOW_FLAGS) + { + permissions = cp & TELEM_PERM_BASE; + } + + if (_prefs.telemetry_mode_loc == TELEM_MODE_ALLOW_ALL) + { + permissions |= TELEM_PERM_LOCATION; + } + else if (_prefs.telemetry_mode_loc == TELEM_MODE_ALLOW_FLAGS) + { + permissions |= cp & TELEM_PERM_LOCATION; + } + + if (_prefs.telemetry_mode_env == TELEM_MODE_ALLOW_ALL) + { + permissions |= TELEM_PERM_ENVIRONMENT; + } + else if (_prefs.telemetry_mode_env == TELEM_MODE_ALLOW_FLAGS) + { + permissions |= cp & TELEM_PERM_ENVIRONMENT; + } + + if (permissions & TELEM_PERM_BASE) + { // only respond if base permission bit is set + telemetry.reset(); + telemetry.addVoltage(TELEM_CHANNEL_SELF, (float)board.getBattMilliVolts() / 1000.0f); + // query other sensors -- target specific + sensors.querySensors(permissions, telemetry); + + memcpy(reply, &sender_timestamp, 4); // reflect sender_timestamp back in response packet (kind of like a 'tag') + + uint8_t tlen = telemetry.getSize(); + memcpy(&reply[4], telemetry.getBuffer(), tlen); + return 4 + tlen; + } + } + return 0; // unknown +} + +void MyMesh::onContactResponse(const ContactInfo &contact, const uint8_t *data, uint8_t len) +{ + uint32_t tag; + memcpy(&tag, data, 4); + + if (pending_login && memcmp(&pending_login, contact.id.pub_key, 4) == 0) + { // check for login response + // yes, is response to pending sendLogin() + pending_login = 0; + + int i = 0; + if (memcmp(&data[4], "OK", 2) == 0) + { // legacy Repeater login OK response + out_frame[i++] = PUSH_CODE_LOGIN_SUCCESS; + out_frame[i++] = 0; // legacy: is_admin = false + memcpy(&out_frame[i], contact.id.pub_key, 6); + i += 6; // pub_key_prefix + } + else if (data[4] == RESP_SERVER_LOGIN_OK) + { // new login response + uint16_t keep_alive_secs = ((uint16_t)data[5]) * 16; + if (keep_alive_secs > 0) + { + startConnection(contact, keep_alive_secs); + } + out_frame[i++] = PUSH_CODE_LOGIN_SUCCESS; + out_frame[i++] = data[6]; // permissions (eg. is_admin) + memcpy(&out_frame[i], contact.id.pub_key, 6); + i += 6; // pub_key_prefix + memcpy(&out_frame[i], &tag, 4); + i += 4; // NEW: include server timestamp + } + else + { + out_frame[i++] = PUSH_CODE_LOGIN_FAIL; + out_frame[i++] = 0; // reserved + memcpy(&out_frame[i], contact.id.pub_key, 6); + i += 6; // pub_key_prefix + } + _serial->writeFrame(out_frame, i); + } + else if (len > 4 && // check for status response + pending_status && memcmp(&pending_status, contact.id.pub_key, 4) == 0 // legacy matching scheme + // FUTURE: tag == pending_status + ) + { + pending_status = 0; + + int i = 0; + out_frame[i++] = PUSH_CODE_STATUS_RESPONSE; + out_frame[i++] = 0; // reserved + memcpy(&out_frame[i], contact.id.pub_key, 6); + i += 6; // pub_key_prefix + memcpy(&out_frame[i], &data[4], len - 4); + i += (len - 4); + _serial->writeFrame(out_frame, i); + } + else if (len > 4 && tag == pending_telemetry) + { // check for telemetry response + pending_telemetry = 0; + + int i = 0; + out_frame[i++] = PUSH_CODE_TELEMETRY_RESPONSE; + out_frame[i++] = 0; // reserved + memcpy(&out_frame[i], contact.id.pub_key, 6); + i += 6; // pub_key_prefix + memcpy(&out_frame[i], &data[4], len - 4); + i += (len - 4); + _serial->writeFrame(out_frame, i); + } +} + +void MyMesh::onRawDataRecv(mesh::Packet *packet) +{ + if (packet->payload_len + 4 > sizeof(out_frame)) + { + MESH_DEBUG_PRINTLN("onRawDataRecv(), payload_len too long: %d", packet->payload_len); + return; + } + int i = 0; + out_frame[i++] = PUSH_CODE_RAW_DATA; + out_frame[i++] = (int8_t)(_radio->getLastSNR() * 4); + out_frame[i++] = (int8_t)(_radio->getLastRSSI()); + out_frame[i++] = 0xFF; // reserved (possibly path_len in future) + memcpy(&out_frame[i], packet->payload, packet->payload_len); + i += packet->payload_len; + + if (_serial->isConnected()) + { + _serial->writeFrame(out_frame, i); + } + else + { + MESH_DEBUG_PRINTLN("onRawDataRecv(), data received while app offline"); + } +} + +void MyMesh::onTraceRecv(mesh::Packet *packet, uint32_t tag, uint32_t auth_code, uint8_t flags, const uint8_t *path_snrs, const uint8_t *path_hashes, uint8_t path_len) +{ + int i = 0; + out_frame[i++] = PUSH_CODE_TRACE_DATA; + out_frame[i++] = 0; // reserved + out_frame[i++] = path_len; + out_frame[i++] = flags; + memcpy(&out_frame[i], &tag, 4); + i += 4; + memcpy(&out_frame[i], &auth_code, 4); + i += 4; + memcpy(&out_frame[i], path_hashes, path_len); + i += path_len; + memcpy(&out_frame[i], path_snrs, path_len); + i += path_len; + out_frame[i++] = (int8_t)(packet->getSNR() * 4); // extra/final SNR (to this node) + + if (_serial->isConnected()) + { + _serial->writeFrame(out_frame, i); + } + else + { + MESH_DEBUG_PRINTLN("onTraceRecv(), data received while app offline"); + } +} + +uint32_t MyMesh::calcFloodTimeoutMillisFor(uint32_t pkt_airtime_millis) const +{ + return SEND_TIMEOUT_BASE_MILLIS + (FLOOD_SEND_TIMEOUT_FACTOR * pkt_airtime_millis); +} +uint32_t MyMesh::calcDirectTimeoutMillisFor(uint32_t pkt_airtime_millis, uint8_t path_len) const +{ + return SEND_TIMEOUT_BASE_MILLIS + + ((pkt_airtime_millis * DIRECT_SEND_PERHOP_FACTOR + DIRECT_SEND_PERHOP_EXTRA_MILLIS) * (path_len + 1)); +} + +void MyMesh::onSendTimeout() +{ +} + +MyMesh::MyMesh(mesh::Radio &radio, mesh::RNG &rng, mesh::RTCClock &rtc, SimpleMeshTables &tables) + : BaseChatMesh(radio, *new ArduinoMillis(), rng, rtc, *new StaticPoolPacketManager(16), tables), _serial(NULL), + telemetry(MAX_PACKET_PAYLOAD - 4) +{ + _iter_started = false; + offline_queue_len = 0; + app_target_ver = 0; + _identity_store = NULL; + pending_login = pending_status = pending_telemetry = 0; + next_ack_idx = 0; + sign_data = NULL; + dirty_contacts_expiry = 0; + + // defaults + memset(&_prefs, 0, sizeof(_prefs)); + _prefs.airtime_factor = 1.0; // one half + strcpy(_prefs.node_name, "NONAME"); + _prefs.freq = LORA_FREQ; + _prefs.sf = LORA_SF; + _prefs.bw = LORA_BW; + _prefs.cr = LORA_CR; + _prefs.tx_power_dbm = LORA_TX_POWER; + //_prefs.rx_delay_base = 10.0f; enable once new algo fixed +} + +void MyMesh::loadPrefsInt(const char *filename) +{ +#if defined(RP2040_PLATFORM) + File file = _fs->open(filename, "r"); +#else + File file = _fs->open(filename); +#endif + if (file) + { + uint8_t pad[8]; + + file.read((uint8_t *)&_prefs.airtime_factor, sizeof(float)); // 0 + file.read((uint8_t *)_prefs.node_name, sizeof(_prefs.node_name)); // 4 + file.read(pad, 4); // 36 + file.read((uint8_t *)&sensors.node_lat, sizeof(sensors.node_lat)); // 40 + file.read((uint8_t *)&sensors.node_lon, sizeof(sensors.node_lon)); // 48 + file.read((uint8_t *)&_prefs.freq, sizeof(_prefs.freq)); // 56 + file.read((uint8_t *)&_prefs.sf, sizeof(_prefs.sf)); // 60 + file.read((uint8_t *)&_prefs.cr, sizeof(_prefs.cr)); // 61 + file.read((uint8_t *)&_prefs.reserved1, sizeof(_prefs.reserved1)); // 62 + file.read((uint8_t *)&_prefs.manual_add_contacts, sizeof(_prefs.manual_add_contacts)); // 63 + file.read((uint8_t *)&_prefs.bw, sizeof(_prefs.bw)); // 64 + file.read((uint8_t *)&_prefs.tx_power_dbm, sizeof(_prefs.tx_power_dbm)); // 68 + file.read((uint8_t *)&_prefs.telemetry_mode_base, sizeof(_prefs.telemetry_mode_base)); // 69 + file.read((uint8_t *)&_prefs.telemetry_mode_loc, sizeof(_prefs.telemetry_mode_loc)); // 70 + file.read((uint8_t *)&_prefs.telemetry_mode_env, sizeof(_prefs.telemetry_mode_env)); // 71 + file.read((uint8_t *)&_prefs.rx_delay_base, sizeof(_prefs.rx_delay_base)); // 72 + file.read(pad, 4); // 76 + file.read((uint8_t *)&_prefs.ble_pin, sizeof(_prefs.ble_pin)); // 80 + + // sanitise bad pref values + _prefs.rx_delay_base = constrain(_prefs.rx_delay_base, 0, 20.0f); + _prefs.airtime_factor = constrain(_prefs.airtime_factor, 0, 9.0f); + _prefs.freq = constrain(_prefs.freq, 400.0f, 2500.0f); + _prefs.bw = constrain(_prefs.bw, 62.5f, 500.0f); + _prefs.sf = constrain(_prefs.sf, 7, 12); + _prefs.cr = constrain(_prefs.cr, 5, 8); + _prefs.tx_power_dbm = constrain(_prefs.tx_power_dbm, 1, MAX_LORA_TX_POWER); + + file.close(); + } +} + +void MyMesh::begin(FILESYSTEM &fs, bool has_display) +{ + _fs = &fs; + + BaseChatMesh::begin(); + +#if defined(NRF52_PLATFORM) || defined(STM32_PLATFORM) + _identity_store = new IdentityStore(fs, ""); +#elif defined(RP2040_PLATFORM) + _identity_store = new IdentityStore(fs, "/identity"); + _identity_store->begin(); +#else + _identity_store = new IdentityStore(fs, "/identity"); +#endif + + loadMainIdentity(); + + // use hex of first 4 bytes of identity public key as default node name + char pub_key_hex[10]; + mesh::Utils::toHex(pub_key_hex, self_id.pub_key, 4); + strcpy(_prefs.node_name, pub_key_hex); + +// if name is provided as a build flag, use that as default node name instead +#ifdef ADVERT_NAME + strcpy(_prefs.node_name, ADVERT_NAME); +#endif + + // load persisted prefs + if (_fs->exists("/new_prefs")) + { + loadPrefsInt("/new_prefs"); // new filename + } + else if (_fs->exists("/node_prefs")) + { + loadPrefsInt("/node_prefs"); + savePrefs(); // save to new filename + _fs->remove("/node_prefs"); // remove old + } + +#ifdef BLE_PIN_CODE + if (_prefs.ble_pin == 0) + { +#ifdef DISPLAY_CLASS + if (has_display) + { + StdRNG rng; + _active_ble_pin = rng.nextInt(100000, 999999); // random pin each session + } + else + { + _active_ble_pin = BLE_PIN_CODE; // otherwise static pin + } +#else + _active_ble_pin = BLE_PIN_CODE; // otherwise static pin +#endif + } + else + { + _active_ble_pin = _prefs.ble_pin; + } +#else + _active_ble_pin = 0; +#endif + + // init 'blob store' support + _fs->mkdir("/bl"); + + loadContacts(); + addChannel("Public", PUBLIC_GROUP_PSK); // pre-configure Andy's public channel + loadChannels(); + + radio_set_params(_prefs.freq, _prefs.bw, _prefs.sf, _prefs.cr); + radio_set_tx_power(_prefs.tx_power_dbm); +} + +const char *MyMesh::getNodeName() { return _prefs.node_name; } +NodePrefs *MyMesh::getNodePrefs() +{ + return &_prefs; +} +uint32_t MyMesh::getBLEPin() { return _active_ble_pin; } + +void MyMesh::startInterface(BaseSerialInterface &serial) +{ + _serial = &serial; + serial.enable(); +} + +void MyMesh::savePrefs() +{ +#if defined(NRF52_PLATFORM) || defined(STM32_PLATFORM) + _fs->remove("/new_prefs"); + File file = _fs->open("/new_prefs", FILE_O_WRITE); +#elif defined(RP2040_PLATFORM) + File file = _fs->open("/new_prefs", "w"); +#else + File file = _fs->open("/new_prefs", "w", true); +#endif + if (file) + { + uint8_t pad[8]; + memset(pad, 0, sizeof(pad)); + + file.write((uint8_t *)&_prefs.airtime_factor, sizeof(float)); // 0 + file.write((uint8_t *)_prefs.node_name, sizeof(_prefs.node_name)); // 4 + file.write(pad, 4); // 36 + file.write((uint8_t *)&sensors.node_lat, sizeof(sensors.node_lat)); // 40 + file.write((uint8_t *)&sensors.node_lon, sizeof(sensors.node_lon)); // 48 + file.write((uint8_t *)&_prefs.freq, sizeof(_prefs.freq)); // 56 + file.write((uint8_t *)&_prefs.sf, sizeof(_prefs.sf)); // 60 + file.write((uint8_t *)&_prefs.cr, sizeof(_prefs.cr)); // 61 + file.write((uint8_t *)&_prefs.reserved1, sizeof(_prefs.reserved1)); // 62 + file.write((uint8_t *)&_prefs.manual_add_contacts, sizeof(_prefs.manual_add_contacts)); // 63 + file.write((uint8_t *)&_prefs.bw, sizeof(_prefs.bw)); // 64 + file.write((uint8_t *)&_prefs.tx_power_dbm, sizeof(_prefs.tx_power_dbm)); // 68 + file.write((uint8_t *)&_prefs.telemetry_mode_base, sizeof(_prefs.telemetry_mode_base)); // 69 + file.write((uint8_t *)&_prefs.telemetry_mode_loc, sizeof(_prefs.telemetry_mode_loc)); // 70 + file.write((uint8_t *)&_prefs.telemetry_mode_env, sizeof(_prefs.telemetry_mode_env)); // 71 + file.write((uint8_t *)&_prefs.rx_delay_base, sizeof(_prefs.rx_delay_base)); // 72 + file.write(pad, 4); // 76 + file.write((uint8_t *)&_prefs.ble_pin, sizeof(_prefs.ble_pin)); // 80 + + file.close(); + } +} + +void MyMesh::handleCmdFrame(size_t len) +{ + if (cmd_frame[0] == CMD_DEVICE_QEURY && len >= 2) + { // sent when app establishes connection + app_target_ver = cmd_frame[1]; // which version of protocol does app understand + + int i = 0; + out_frame[i++] = RESP_CODE_DEVICE_INFO; + out_frame[i++] = FIRMWARE_VER_CODE; + out_frame[i++] = MAX_CONTACTS / 2; // v3+ + out_frame[i++] = MAX_GROUP_CHANNELS; // v3+ + memcpy(&out_frame[i], &_prefs.ble_pin, 4); + i += 4; + memset(&out_frame[i], 0, 12); + strcpy((char *)&out_frame[i], FIRMWARE_BUILD_DATE); + i += 12; + StrHelper::strzcpy((char *)&out_frame[i], board.getManufacturerName(), 40); + i += 40; + StrHelper::strzcpy((char *)&out_frame[i], FIRMWARE_VERSION, 20); + i += 20; + _serial->writeFrame(out_frame, i); + } + else if (cmd_frame[0] == CMD_APP_START && len >= 8) + { // sent when app establishes connection, respond with node ID + // cmd_frame[1..7] reserved future + char *app_name = (char *)&cmd_frame[8]; + cmd_frame[len] = 0; // make app_name null terminated + MESH_DEBUG_PRINTLN("App %s connected", app_name); + + _iter_started = false; // stop any left-over ContactsIterator + int i = 0; + out_frame[i++] = RESP_CODE_SELF_INFO; + out_frame[i++] = ADV_TYPE_CHAT; // what this node Advert identifies as (maybe node's pronouns too?? :-) + out_frame[i++] = _prefs.tx_power_dbm; + out_frame[i++] = MAX_LORA_TX_POWER; + memcpy(&out_frame[i], self_id.pub_key, PUB_KEY_SIZE); + i += PUB_KEY_SIZE; + + int32_t lat, lon; + lat = (sensors.node_lat * 1000000.0); + lon = (sensors.node_lon * 1000000.0); + memcpy(&out_frame[i], &lat, 4); + i += 4; + memcpy(&out_frame[i], &lon, 4); + i += 4; + out_frame[i++] = 0; // reserved + out_frame[i++] = 0; // reserved + out_frame[i++] = (_prefs.telemetry_mode_env << 4) | (_prefs.telemetry_mode_loc << 2) | (_prefs.telemetry_mode_base); // v5+ + out_frame[i++] = _prefs.manual_add_contacts; + + uint32_t freq = _prefs.freq * 1000; + memcpy(&out_frame[i], &freq, 4); + i += 4; + uint32_t bw = _prefs.bw * 1000; + memcpy(&out_frame[i], &bw, 4); + i += 4; + out_frame[i++] = _prefs.sf; + out_frame[i++] = _prefs.cr; + + int tlen = strlen(_prefs.node_name); // revisit: UTF_8 ?? + memcpy(&out_frame[i], _prefs.node_name, tlen); + i += tlen; + _serial->writeFrame(out_frame, i); + } + else if (cmd_frame[0] == CMD_SEND_TXT_MSG && len >= 14) + { + int i = 1; + uint8_t txt_type = cmd_frame[i++]; + uint8_t attempt = cmd_frame[i++]; + uint32_t msg_timestamp; + memcpy(&msg_timestamp, &cmd_frame[i], 4); + i += 4; + uint8_t *pub_key_prefix = &cmd_frame[i]; + i += 6; + ContactInfo *recipient = lookupContactByPubKey(pub_key_prefix, 6); + if (recipient && (txt_type == TXT_TYPE_PLAIN || txt_type == TXT_TYPE_CLI_DATA)) + { + char *text = (char *)&cmd_frame[i]; + int tlen = len - i; + uint32_t est_timeout; + text[tlen] = 0; // ensure null + int result; + uint32_t expected_ack; + if (txt_type == TXT_TYPE_CLI_DATA) + { + result = sendCommandData(*recipient, msg_timestamp, attempt, text, est_timeout); + expected_ack = 0; // no Ack expected + } + else + { + result = sendMessage(*recipient, msg_timestamp, attempt, text, expected_ack, est_timeout); + } + // TODO: add expected ACK to table + if (result == MSG_SEND_FAILED) + { + writeErrFrame(ERR_CODE_TABLE_FULL); + } + else + { + if (expected_ack) + { + expected_ack_table[next_ack_idx].msg_sent = _ms->getMillis(); // add to circular table + expected_ack_table[next_ack_idx].ack = expected_ack; + next_ack_idx = (next_ack_idx + 1) % EXPECTED_ACK_TABLE_SIZE; + } + + out_frame[0] = RESP_CODE_SENT; + out_frame[1] = (result == MSG_SEND_SENT_FLOOD) ? 1 : 0; + memcpy(&out_frame[2], &expected_ack, 4); + memcpy(&out_frame[6], &est_timeout, 4); + _serial->writeFrame(out_frame, 10); + } + } + else + { + writeErrFrame(recipient == NULL ? ERR_CODE_NOT_FOUND : ERR_CODE_UNSUPPORTED_CMD); // unknown recipient, or unsuported TXT_TYPE_* + } + } + else if (cmd_frame[0] == CMD_SEND_CHANNEL_TXT_MSG) + { // send GroupChannel msg + int i = 1; + uint8_t txt_type = cmd_frame[i++]; // should be TXT_TYPE_PLAIN + uint8_t channel_idx = cmd_frame[i++]; + uint32_t msg_timestamp; + memcpy(&msg_timestamp, &cmd_frame[i], 4); + i += 4; + const char *text = (char *)&cmd_frame[i]; + + if (txt_type != TXT_TYPE_PLAIN) + { + writeErrFrame(ERR_CODE_UNSUPPORTED_CMD); + } + else + { + ChannelDetails channel; + bool success = getChannel(channel_idx, channel); + if (success && sendGroupMessage(msg_timestamp, channel.channel, _prefs.node_name, text, len - i)) + { + writeOKFrame(); + } + else + { + writeErrFrame(ERR_CODE_NOT_FOUND); // bad channel_idx + } + } + } + else if (cmd_frame[0] == CMD_GET_CONTACTS) + { // get Contact list + if (_iter_started) + { + writeErrFrame(ERR_CODE_BAD_STATE); // iterator is currently busy + } + else + { + if (len >= 5) + { // has optional 'since' param + memcpy(&_iter_filter_since, &cmd_frame[1], 4); + } + else + { + _iter_filter_since = 0; + } + + uint8_t reply[5]; + reply[0] = RESP_CODE_CONTACTS_START; + uint32_t count = getNumContacts(); // total, NOT filtered count + memcpy(&reply[1], &count, 4); + _serial->writeFrame(reply, 5); + + // start iterator + _iter = startContactsIterator(); + _iter_started = true; + _most_recent_lastmod = 0; + } + } + else if (cmd_frame[0] == CMD_SET_ADVERT_NAME && len >= 2) + { + int nlen = len - 1; + if (nlen > sizeof(_prefs.node_name) - 1) + nlen = sizeof(_prefs.node_name) - 1; // max len + memcpy(_prefs.node_name, &cmd_frame[1], nlen); + _prefs.node_name[nlen] = 0; // null terminator + savePrefs(); + writeOKFrame(); + } + else if (cmd_frame[0] == CMD_SET_ADVERT_LATLON && len >= 9) + { + int32_t lat, lon, alt = 0; + memcpy(&lat, &cmd_frame[1], 4); + memcpy(&lon, &cmd_frame[5], 4); + if (len >= 13) + { + memcpy(&alt, &cmd_frame[9], 4); // for FUTURE support + } + if (lat <= 90 * 1E6 && lat >= -90 * 1E6 && lon <= 180 * 1E6 && lon >= -180 * 1E6) + { + sensors.node_lat = ((double)lat) / 1000000.0; + sensors.node_lon = ((double)lon) / 1000000.0; + savePrefs(); + writeOKFrame(); + } + else + { + writeErrFrame(ERR_CODE_ILLEGAL_ARG); // invalid geo coordinate + } + } + else if (cmd_frame[0] == CMD_GET_DEVICE_TIME) + { + uint8_t reply[5]; + reply[0] = RESP_CODE_CURR_TIME; + uint32_t now = getRTCClock()->getCurrentTime(); + memcpy(&reply[1], &now, 4); + _serial->writeFrame(reply, 5); + } + else if (cmd_frame[0] == CMD_SET_DEVICE_TIME && len >= 5) + { + uint32_t secs; + memcpy(&secs, &cmd_frame[1], 4); + uint32_t curr = getRTCClock()->getCurrentTime(); + if (secs >= curr) + { + getRTCClock()->setCurrentTime(secs); + writeOKFrame(); + } + else + { + writeErrFrame(ERR_CODE_ILLEGAL_ARG); + } + } + else if (cmd_frame[0] == CMD_SEND_SELF_ADVERT) + { + auto pkt = createSelfAdvert(_prefs.node_name, sensors.node_lat, sensors.node_lon); + if (pkt) + { + if (len >= 2 && cmd_frame[1] == 1) + { // optional param (1 = flood, 0 = zero hop) + sendFlood(pkt); + } + else + { + sendZeroHop(pkt); + } + writeOKFrame(); + } + else + { + writeErrFrame(ERR_CODE_TABLE_FULL); + } + } + else if (cmd_frame[0] == CMD_RESET_PATH && len >= 1 + 32) + { + uint8_t *pub_key = &cmd_frame[1]; + ContactInfo *recipient = lookupContactByPubKey(pub_key, PUB_KEY_SIZE); + if (recipient) + { + recipient->out_path_len = -1; + // recipient->lastmod = ?? shouldn't be needed, app already has this version of contact + dirty_contacts_expiry = futureMillis(LAZY_CONTACTS_WRITE_DELAY); + writeOKFrame(); + } + else + { + writeErrFrame(ERR_CODE_NOT_FOUND); // unknown contact + } + } + else if (cmd_frame[0] == CMD_ADD_UPDATE_CONTACT && len >= 1 + 32 + 2 + 1) + { + uint8_t *pub_key = &cmd_frame[1]; + ContactInfo *recipient = lookupContactByPubKey(pub_key, PUB_KEY_SIZE); + if (recipient) + { + updateContactFromFrame(*recipient, cmd_frame, len); + // recipient->lastmod = ?? shouldn't be needed, app already has this version of contact + dirty_contacts_expiry = futureMillis(LAZY_CONTACTS_WRITE_DELAY); + writeOKFrame(); + } + else + { + ContactInfo contact; + updateContactFromFrame(contact, cmd_frame, len); + contact.lastmod = getRTCClock()->getCurrentTime(); + contact.sync_since = 0; + if (addContact(contact)) + { + dirty_contacts_expiry = futureMillis(LAZY_CONTACTS_WRITE_DELAY); + writeOKFrame(); + } + else + { + writeErrFrame(ERR_CODE_TABLE_FULL); + } + } + } + else if (cmd_frame[0] == CMD_REMOVE_CONTACT) + { + uint8_t *pub_key = &cmd_frame[1]; + ContactInfo *recipient = lookupContactByPubKey(pub_key, PUB_KEY_SIZE); + if (recipient && removeContact(*recipient)) + { + dirty_contacts_expiry = futureMillis(LAZY_CONTACTS_WRITE_DELAY); + writeOKFrame(); + } + else + { + writeErrFrame(ERR_CODE_NOT_FOUND); // not found, or unable to remove + } + } + else if (cmd_frame[0] == CMD_SHARE_CONTACT) + { + uint8_t *pub_key = &cmd_frame[1]; + ContactInfo *recipient = lookupContactByPubKey(pub_key, PUB_KEY_SIZE); + if (recipient) + { + if (shareContactZeroHop(*recipient)) + { + writeOKFrame(); + } + else + { + writeErrFrame(ERR_CODE_TABLE_FULL); // unable to send + } + } + else + { + writeErrFrame(ERR_CODE_NOT_FOUND); + } + } + else if (cmd_frame[0] == CMD_GET_CONTACT_BY_KEY) + { + uint8_t *pub_key = &cmd_frame[1]; + ContactInfo *contact = lookupContactByPubKey(pub_key, PUB_KEY_SIZE); + if (contact) + { + writeContactRespFrame(RESP_CODE_CONTACT, *contact); + } + else + { + writeErrFrame(ERR_CODE_NOT_FOUND); // not found + } + } + else if (cmd_frame[0] == CMD_EXPORT_CONTACT) + { + if (len < 1 + PUB_KEY_SIZE) + { + // export SELF + auto pkt = createSelfAdvert(_prefs.node_name, sensors.node_lat, sensors.node_lon); + if (pkt) + { + pkt->header |= ROUTE_TYPE_FLOOD; // would normally be sent in this mode + + out_frame[0] = RESP_CODE_EXPORT_CONTACT; + uint8_t out_len = pkt->writeTo(&out_frame[1]); + releasePacket(pkt); // undo the obtainNewPacket() + _serial->writeFrame(out_frame, out_len + 1); + } + else + { + writeErrFrame(ERR_CODE_TABLE_FULL); // Error + } + } + else + { + uint8_t *pub_key = &cmd_frame[1]; + ContactInfo *recipient = lookupContactByPubKey(pub_key, PUB_KEY_SIZE); + uint8_t out_len; + if (recipient && (out_len = exportContact(*recipient, &out_frame[1])) > 0) + { + out_frame[0] = RESP_CODE_EXPORT_CONTACT; + _serial->writeFrame(out_frame, out_len + 1); + } + else + { + writeErrFrame(ERR_CODE_NOT_FOUND); // not found + } + } + } + else if (cmd_frame[0] == CMD_IMPORT_CONTACT && len > 2 + 32 + 64) + { + if (importContact(&cmd_frame[1], len - 1)) + { + writeOKFrame(); + } + else + { + writeErrFrame(ERR_CODE_ILLEGAL_ARG); + } + } + else if (cmd_frame[0] == CMD_SYNC_NEXT_MESSAGE) + { + int out_len; + if ((out_len = getFromOfflineQueue(out_frame)) > 0) + { + _serial->writeFrame(out_frame, out_len); +#ifdef DISPLAY_CLASS + ui_task.msgRead(offline_queue_len); +#endif + } + else + { + out_frame[0] = RESP_CODE_NO_MORE_MESSAGES; + _serial->writeFrame(out_frame, 1); + } + } + else if (cmd_frame[0] == CMD_SET_RADIO_PARAMS) + { + int i = 1; + uint32_t freq; + memcpy(&freq, &cmd_frame[i], 4); + i += 4; + uint32_t bw; + memcpy(&bw, &cmd_frame[i], 4); + i += 4; + uint8_t sf = cmd_frame[i++]; + uint8_t cr = cmd_frame[i++]; + + if (freq >= 300000 && freq <= 2500000 && sf >= 7 && sf <= 12 && cr >= 5 && cr <= 8 && bw >= 7000 && bw <= 500000) + { + _prefs.sf = sf; + _prefs.cr = cr; + _prefs.freq = (float)freq / 1000.0; + _prefs.bw = (float)bw / 1000.0; + savePrefs(); + + radio_set_params(_prefs.freq, _prefs.bw, _prefs.sf, _prefs.cr); + MESH_DEBUG_PRINTLN("OK: CMD_SET_RADIO_PARAMS: f=%d, bw=%d, sf=%d, cr=%d", freq, bw, (uint32_t)sf, (uint32_t)cr); + + writeOKFrame(); + } + else + { + MESH_DEBUG_PRINTLN("Error: CMD_SET_RADIO_PARAMS: f=%d, bw=%d, sf=%d, cr=%d", freq, bw, (uint32_t)sf, (uint32_t)cr); + writeErrFrame(ERR_CODE_ILLEGAL_ARG); + } + } + else if (cmd_frame[0] == CMD_SET_RADIO_TX_POWER) + { + if (cmd_frame[1] > MAX_LORA_TX_POWER) + { + writeErrFrame(ERR_CODE_ILLEGAL_ARG); + } + else + { + _prefs.tx_power_dbm = cmd_frame[1]; + savePrefs(); + radio_set_tx_power(_prefs.tx_power_dbm); + writeOKFrame(); + } + } + else if (cmd_frame[0] == CMD_SET_TUNING_PARAMS) + { + int i = 1; + uint32_t rx, af; + memcpy(&rx, &cmd_frame[i], 4); + i += 4; + memcpy(&af, &cmd_frame[i], 4); + i += 4; + _prefs.rx_delay_base = ((float)rx) / 1000.0f; + _prefs.airtime_factor = ((float)af) / 1000.0f; + savePrefs(); + writeOKFrame(); + } + else if (cmd_frame[0] == CMD_SET_OTHER_PARAMS) + { + _prefs.manual_add_contacts = cmd_frame[1]; + if (len >= 3) + { + _prefs.telemetry_mode_base = cmd_frame[2] & 0x03; // v5+ + _prefs.telemetry_mode_loc = (cmd_frame[2] >> 2) & 0x03; + _prefs.telemetry_mode_env = (cmd_frame[2] >> 4) & 0x03; + } + savePrefs(); + writeOKFrame(); + } + else if (cmd_frame[0] == CMD_REBOOT && memcmp(&cmd_frame[1], "reboot", 6) == 0) + { + if (dirty_contacts_expiry) + { // is there are pending dirty contacts write needed? + saveContacts(); + } + board.reboot(); + } + else if (cmd_frame[0] == CMD_GET_BATTERY_VOLTAGE) + { + uint8_t reply[3]; + reply[0] = RESP_CODE_BATTERY_VOLTAGE; + uint16_t battery_millivolts = board.getBattMilliVolts(); + memcpy(&reply[1], &battery_millivolts, 2); + _serial->writeFrame(reply, 3); + } + else if (cmd_frame[0] == CMD_EXPORT_PRIVATE_KEY) + { +#if ENABLE_PRIVATE_KEY_EXPORT + uint8_t reply[65]; + reply[0] = RESP_CODE_PRIVATE_KEY; + self_id.writeTo(&reply[1], 64); + _serial->writeFrame(reply, 65); +#else + writeDisabledFrame(); +#endif + } + else if (cmd_frame[0] == CMD_IMPORT_PRIVATE_KEY && len >= 65) + { +#if ENABLE_PRIVATE_KEY_IMPORT + mesh::LocalIdentity identity; + identity.readFrom(&cmd_frame[1], 64); + if (saveMainIdentity(identity)) + { + self_id = identity; + writeOKFrame(); + } + else + { + writeErrFrame(ERR_CODE_FILE_IO_ERROR); + } +#else + writeDisabledFrame(); +#endif + } + else if (cmd_frame[0] == CMD_SEND_RAW_DATA && len >= 6) + { + int i = 1; + int8_t path_len = cmd_frame[i++]; + if (path_len >= 0 && i + path_len + 4 <= len) + { // minimum 4 byte payload + uint8_t *path = &cmd_frame[i]; + i += path_len; + auto pkt = createRawData(&cmd_frame[i], len - i); + if (pkt) + { + sendDirect(pkt, path, path_len); + writeOKFrame(); + } + else + { + writeErrFrame(ERR_CODE_TABLE_FULL); + } + } + else + { + writeErrFrame(ERR_CODE_UNSUPPORTED_CMD); // flood, not supported (yet) + } + } + else if (cmd_frame[0] == CMD_SEND_LOGIN && len >= 1 + PUB_KEY_SIZE) + { + uint8_t *pub_key = &cmd_frame[1]; + ContactInfo *recipient = lookupContactByPubKey(pub_key, PUB_KEY_SIZE); + char *password = (char *)&cmd_frame[1 + PUB_KEY_SIZE]; + cmd_frame[len] = 0; // ensure null terminator in password + if (recipient) + { + uint32_t est_timeout; + int result = sendLogin(*recipient, password, est_timeout); + if (result == MSG_SEND_FAILED) + { + writeErrFrame(ERR_CODE_TABLE_FULL); + } + else + { + pending_telemetry = pending_status = 0; + memcpy(&pending_login, recipient->id.pub_key, 4); // match this to onContactResponse() + out_frame[0] = RESP_CODE_SENT; + out_frame[1] = (result == MSG_SEND_SENT_FLOOD) ? 1 : 0; + memcpy(&out_frame[2], &pending_login, 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) + { + uint8_t *pub_key = &cmd_frame[1]; + ContactInfo *recipient = lookupContactByPubKey(pub_key, PUB_KEY_SIZE); + if (recipient) + { + uint32_t tag, est_timeout; + int result = sendRequest(*recipient, REQ_TYPE_GET_STATUS, tag, est_timeout); + if (result == MSG_SEND_FAILED) + { + writeErrFrame(ERR_CODE_TABLE_FULL); + } + else + { + pending_telemetry = pending_login = 0; + // FUTURE: pending_status = tag; // match this in onContactResponse() + memcpy(&pending_status, recipient->id.pub_key, 4); // legacy matching scheme + 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_TELEMETRY_REQ && len >= 4 + PUB_KEY_SIZE) + { + uint8_t *pub_key = &cmd_frame[4]; + ContactInfo *recipient = lookupContactByPubKey(pub_key, PUB_KEY_SIZE); + if (recipient) + { + uint32_t tag, est_timeout; + int result = sendRequest(*recipient, REQ_TYPE_GET_TELEMETRY_DATA, tag, est_timeout); + if (result == MSG_SEND_FAILED) + { + writeErrFrame(ERR_CODE_TABLE_FULL); + } + else + { + pending_status = pending_login = 0; + pending_telemetry = tag; // match this in 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_HAS_CONNECTION && len >= 1 + PUB_KEY_SIZE) + { + uint8_t *pub_key = &cmd_frame[1]; + if (hasConnectionTo(pub_key)) + { + writeOKFrame(); + } + else + { + writeErrFrame(ERR_CODE_NOT_FOUND); + } + } + else if (cmd_frame[0] == CMD_LOGOUT && len >= 1 + PUB_KEY_SIZE) + { + uint8_t *pub_key = &cmd_frame[1]; + stopConnection(pub_key); + writeOKFrame(); + } + else if (cmd_frame[0] == CMD_GET_CHANNEL && len >= 2) + { + uint8_t channel_idx = cmd_frame[1]; + ChannelDetails channel; + if (getChannel(channel_idx, channel)) + { + int i = 0; + out_frame[i++] = RESP_CODE_CHANNEL_INFO; + out_frame[i++] = channel_idx; + strcpy((char *)&out_frame[i], channel.name); + i += 32; + memcpy(&out_frame[i], channel.channel.secret, 16); + i += 16; // NOTE: only 128-bit supported + _serial->writeFrame(out_frame, i); + } + else + { + writeErrFrame(ERR_CODE_NOT_FOUND); + } + } + else if (cmd_frame[0] == CMD_SET_CHANNEL && len >= 2 + 32 + 32) + { + writeErrFrame(ERR_CODE_UNSUPPORTED_CMD); // not supported (yet) + } + else if (cmd_frame[0] == CMD_SET_CHANNEL && len >= 2 + 32 + 16) + { + uint8_t channel_idx = cmd_frame[1]; + ChannelDetails channel; + StrHelper::strncpy(channel.name, (char *)&cmd_frame[2], 32); + memset(channel.channel.secret, 0, sizeof(channel.channel.secret)); + memcpy(channel.channel.secret, &cmd_frame[2 + 32], 16); // NOTE: only 128-bit supported + if (setChannel(channel_idx, channel)) + { + saveChannels(); + writeOKFrame(); + } + else + { + writeErrFrame(ERR_CODE_NOT_FOUND); // bad channel_idx + } + } + else if (cmd_frame[0] == CMD_SIGN_START) + { + out_frame[0] = RESP_CODE_SIGN_START; + out_frame[1] = 0; // reserved + uint32_t len = MAX_SIGN_DATA_LEN; + memcpy(&out_frame[2], &len, 4); + _serial->writeFrame(out_frame, 6); + + if (sign_data) + { + free(sign_data); + } + sign_data = (uint8_t *)malloc(MAX_SIGN_DATA_LEN); + sign_data_len = 0; + } + else if (cmd_frame[0] == CMD_SIGN_DATA && len > 1) + { + if (sign_data == NULL || sign_data_len + (len - 1) > MAX_SIGN_DATA_LEN) + { + writeErrFrame(sign_data == NULL ? ERR_CODE_BAD_STATE : ERR_CODE_TABLE_FULL); // error: too long + } + else + { + memcpy(&sign_data[sign_data_len], &cmd_frame[1], len - 1); + sign_data_len += (len - 1); + writeOKFrame(); + } + } + else if (cmd_frame[0] == CMD_SIGN_FINISH) + { + if (sign_data) + { + self_id.sign(&out_frame[1], sign_data, sign_data_len); + + free(sign_data); // don't need sign_data now + sign_data = NULL; + + out_frame[0] = RESP_CODE_SIGNATURE; + _serial->writeFrame(out_frame, 1 + SIGNATURE_SIZE); + } + else + { + writeErrFrame(ERR_CODE_BAD_STATE); + } + } + else if (cmd_frame[0] == CMD_SEND_TRACE_PATH && len > 10 && len - 10 < MAX_PATH_SIZE) + { + uint32_t tag, auth; + memcpy(&tag, &cmd_frame[1], 4); + memcpy(&auth, &cmd_frame[5], 4); + auto pkt = createTrace(tag, auth, cmd_frame[9]); + if (pkt) + { + uint8_t path_len = len - 10; + sendDirect(pkt, &cmd_frame[10], path_len); + + uint32_t t = _radio->getEstAirtimeFor(pkt->payload_len + pkt->path_len + 2); + uint32_t est_timeout = calcDirectTimeoutMillisFor(t, path_len); + + out_frame[0] = RESP_CODE_SENT; + out_frame[1] = 0; + memcpy(&out_frame[2], &tag, 4); + memcpy(&out_frame[6], &est_timeout, 4); + _serial->writeFrame(out_frame, 10); + } + else + { + writeErrFrame(ERR_CODE_TABLE_FULL); + } + } + else if (cmd_frame[0] == CMD_SET_DEVICE_PIN && len >= 5) + { + + // get pin from command frame + uint32_t pin; + memcpy(&pin, &cmd_frame[1], 4); + + // ensure pin is zero, or a valid 6 digit pin + if (pin == 0 || (pin >= 100000 && pin <= 999999)) + { + _prefs.ble_pin = pin; + savePrefs(); + writeOKFrame(); + } + else + { + writeErrFrame(ERR_CODE_ILLEGAL_ARG); + } + } + else if (cmd_frame[0] == CMD_GET_CUSTOM_VARS) + { + out_frame[0] = RESP_CODE_CUSTOM_VARS; + char *dp = (char *)&out_frame[1]; + for (int i = 0; i < sensors.getNumSettings() && dp - (char *)&out_frame[1] < 140; i++) + { + if (i > 0) + { + *dp++ = ','; + } + strcpy(dp, sensors.getSettingName(i)); + dp = strchr(dp, 0); + *dp++ = ':'; + strcpy(dp, sensors.getSettingValue(i)); + dp = strchr(dp, 0); + } + _serial->writeFrame(out_frame, dp - (char *)out_frame); + } + else if (cmd_frame[0] == CMD_SET_CUSTOM_VAR && len >= 4) + { + cmd_frame[len] = 0; + char *sp = (char *)&cmd_frame[1]; + char *np = strchr(sp, ':'); // look for separator char + if (np) + { + *np++ = 0; // modify 'cmd_frame', replace ':' with null + bool success = sensors.setSettingValue(sp, np); + if (success) + { + writeOKFrame(); + } + else + { + writeErrFrame(ERR_CODE_ILLEGAL_ARG); + } + } + else + { + writeErrFrame(ERR_CODE_ILLEGAL_ARG); + } + } + else + { + writeErrFrame(ERR_CODE_UNSUPPORTED_CMD); + MESH_DEBUG_PRINTLN("ERROR: unknown command: %02X", cmd_frame[0]); + } +} + +void MyMesh::loop() +{ + BaseChatMesh::loop(); + + size_t len = _serial->checkRecvFrame(cmd_frame); + if (len > 0) + { + handleCmdFrame(len); + } + else if (_iter_started // check if our ContactsIterator is 'running' + && !_serial->isWriteBusy() // don't spam the Serial Interface too quickly! + ) + { + ContactInfo contact; + if (_iter.hasNext(this, contact)) + { + if (contact.lastmod > _iter_filter_since) + { // apply the 'since' filter + writeContactRespFrame(RESP_CODE_CONTACT, contact); + if (contact.lastmod > _most_recent_lastmod) + { + _most_recent_lastmod = contact.lastmod; // save for the RESP_CODE_END_OF_CONTACTS frame + } + } + } + else + { // EOF + out_frame[0] = RESP_CODE_END_OF_CONTACTS; + memcpy(&out_frame[1], &_most_recent_lastmod, 4); // include the most recent lastmod, so app can update their 'since' + _serial->writeFrame(out_frame, 5); + _iter_started = false; + } + } + else if (!_serial->isWriteBusy()) + { + checkConnections(); + } + + // is there are pending dirty contacts write needed? + if (dirty_contacts_expiry && millisHasNowPassed(dirty_contacts_expiry)) + { + saveContacts(); + dirty_contacts_expiry = 0; + } + +#ifdef DISPLAY_CLASS + ui_task.setHasConnection(_serial->isConnected()); + ui_task.loop(); +#endif +} + +bool MyMesh::advert() +{ + auto pkt = createSelfAdvert(_prefs.node_name, sensors.node_lat, sensors.node_lon); + if (pkt) + { + sendZeroHop(pkt); + writeOKFrame(); + return true; + } + else + { + writeErrFrame(ERR_CODE_TABLE_FULL); + return false; + } +} \ No newline at end of file diff --git a/examples/companion_radio/MyMesh.h b/examples/companion_radio/MyMesh.h new file mode 100644 index 000000000..a4794f1f1 --- /dev/null +++ b/examples/companion_radio/MyMesh.h @@ -0,0 +1,283 @@ +#ifndef MYMESH_H +#define MYMESH_H + +#include +#include +#ifdef DISPLAY_CLASS + #include "UITask.h" +#endif + +/*------------ Frame Protocol --------------*/ +#define FIRMWARE_VER_CODE 5 + +#ifndef FIRMWARE_BUILD_DATE + #define FIRMWARE_BUILD_DATE "24 May 2025" +#endif + +#ifndef FIRMWARE_VERSION + #define FIRMWARE_VERSION "v1.6.2" +#endif + +#if defined(NRF52_PLATFORM) || defined(STM32_PLATFORM) +#include +#elif defined(RP2040_PLATFORM) +#include +#elif defined(ESP32) +#include +#endif + +#include +#include +#include +#include +#include +#include "NodePrefs.h" +#include +#include + +/* ---------------------------------- CONFIGURATION ------------------------------------- */ + +#ifndef LORA_FREQ + #define LORA_FREQ 915.0 +#endif +#ifndef LORA_BW + #define LORA_BW 250 +#endif +#ifndef LORA_SF + #define LORA_SF 10 +#endif +#ifndef LORA_CR + #define LORA_CR 5 +#endif +#ifndef LORA_TX_POWER + #define LORA_TX_POWER 20 +#endif +#ifndef MAX_LORA_TX_POWER + #define MAX_LORA_TX_POWER LORA_TX_POWER +#endif + +#ifndef MAX_CONTACTS + #define MAX_CONTACTS 100 +#endif + +#ifndef OFFLINE_QUEUE_SIZE + #define OFFLINE_QUEUE_SIZE 16 +#endif + +#ifndef BLE_NAME_PREFIX + #define BLE_NAME_PREFIX "MeshCore-" +#endif + +#include + +#define SEND_TIMEOUT_BASE_MILLIS 500 +#define FLOOD_SEND_TIMEOUT_FACTOR 16.0f +#define DIRECT_SEND_PERHOP_FACTOR 6.0f +#define DIRECT_SEND_PERHOP_EXTRA_MILLIS 250 +#define LAZY_CONTACTS_WRITE_DELAY 5000 + +#define PUBLIC_GROUP_PSK "izOH6cXN6mrJ5e26oRXNcg==" + +#define CMD_APP_START 1 +#define CMD_SEND_TXT_MSG 2 +#define CMD_SEND_CHANNEL_TXT_MSG 3 +#define CMD_GET_CONTACTS 4 // with optional 'since' (for efficient sync) +#define CMD_GET_DEVICE_TIME 5 +#define CMD_SET_DEVICE_TIME 6 +#define CMD_SEND_SELF_ADVERT 7 +#define CMD_SET_ADVERT_NAME 8 +#define CMD_ADD_UPDATE_CONTACT 9 +#define CMD_SYNC_NEXT_MESSAGE 10 +#define CMD_SET_RADIO_PARAMS 11 +#define CMD_SET_RADIO_TX_POWER 12 +#define CMD_RESET_PATH 13 +#define CMD_SET_ADVERT_LATLON 14 +#define CMD_REMOVE_CONTACT 15 +#define CMD_SHARE_CONTACT 16 +#define CMD_EXPORT_CONTACT 17 +#define CMD_IMPORT_CONTACT 18 +#define CMD_REBOOT 19 +#define CMD_GET_BATTERY_VOLTAGE 20 +#define CMD_SET_TUNING_PARAMS 21 +#define CMD_DEVICE_QEURY 22 +#define CMD_EXPORT_PRIVATE_KEY 23 +#define CMD_IMPORT_PRIVATE_KEY 24 +#define CMD_SEND_RAW_DATA 25 +#define CMD_SEND_LOGIN 26 +#define CMD_SEND_STATUS_REQ 27 +#define CMD_HAS_CONNECTION 28 +#define CMD_LOGOUT 29 // 'Disconnect' +#define CMD_GET_CONTACT_BY_KEY 30 +#define CMD_GET_CHANNEL 31 +#define CMD_SET_CHANNEL 32 +#define CMD_SIGN_START 33 +#define CMD_SIGN_DATA 34 +#define CMD_SIGN_FINISH 35 +#define CMD_SEND_TRACE_PATH 36 +#define CMD_SET_DEVICE_PIN 37 +#define CMD_SET_OTHER_PARAMS 38 +#define CMD_SEND_TELEMETRY_REQ 39 +#define CMD_GET_CUSTOM_VARS 40 +#define CMD_SET_CUSTOM_VAR 41 + +#define RESP_CODE_OK 0 +#define RESP_CODE_ERR 1 +#define RESP_CODE_CONTACTS_START 2 // first reply to CMD_GET_CONTACTS +#define RESP_CODE_CONTACT 3 // multiple of these (after CMD_GET_CONTACTS) +#define RESP_CODE_END_OF_CONTACTS 4 // last reply to CMD_GET_CONTACTS +#define RESP_CODE_SELF_INFO 5 // reply to CMD_APP_START +#define RESP_CODE_SENT 6 // reply to CMD_SEND_TXT_MSG +#define RESP_CODE_CONTACT_MSG_RECV 7 // a reply to CMD_SYNC_NEXT_MESSAGE (ver < 3) +#define RESP_CODE_CHANNEL_MSG_RECV 8 // a reply to CMD_SYNC_NEXT_MESSAGE (ver < 3) +#define RESP_CODE_CURR_TIME 9 // a reply to CMD_GET_DEVICE_TIME +#define RESP_CODE_NO_MORE_MESSAGES 10 // a reply to CMD_SYNC_NEXT_MESSAGE +#define RESP_CODE_EXPORT_CONTACT 11 +#define RESP_CODE_BATTERY_VOLTAGE 12 // a reply to a CMD_GET_BATTERY_VOLTAGE +#define RESP_CODE_DEVICE_INFO 13 // a reply to CMD_DEVICE_QEURY +#define RESP_CODE_PRIVATE_KEY 14 // a reply to CMD_EXPORT_PRIVATE_KEY +#define RESP_CODE_DISABLED 15 +#define RESP_CODE_CONTACT_MSG_RECV_V3 16 // a reply to CMD_SYNC_NEXT_MESSAGE (ver >= 3) +#define RESP_CODE_CHANNEL_MSG_RECV_V3 17 // a reply to CMD_SYNC_NEXT_MESSAGE (ver >= 3) +#define RESP_CODE_CHANNEL_INFO 18 // a reply to CMD_GET_CHANNEL +#define RESP_CODE_SIGN_START 19 +#define RESP_CODE_SIGNATURE 20 +#define RESP_CODE_CUSTOM_VARS 21 + +// these are _pushed_ to client app at any time +#define PUSH_CODE_ADVERT 0x80 +#define PUSH_CODE_PATH_UPDATED 0x81 +#define PUSH_CODE_SEND_CONFIRMED 0x82 +#define PUSH_CODE_MSG_WAITING 0x83 +#define PUSH_CODE_RAW_DATA 0x84 +#define PUSH_CODE_LOGIN_SUCCESS 0x85 +#define PUSH_CODE_LOGIN_FAIL 0x86 +#define PUSH_CODE_STATUS_RESPONSE 0x87 +#define PUSH_CODE_LOG_RX_DATA 0x88 +#define PUSH_CODE_TRACE_DATA 0x89 +#define PUSH_CODE_NEW_ADVERT 0x8A +#define PUSH_CODE_TELEMETRY_RESPONSE 0x8B + +#define ERR_CODE_UNSUPPORTED_CMD 1 +#define ERR_CODE_NOT_FOUND 2 +#define ERR_CODE_TABLE_FULL 3 +#define ERR_CODE_BAD_STATE 4 +#define ERR_CODE_FILE_IO_ERROR 5 +#define ERR_CODE_ILLEGAL_ARG 6 + +/* -------------------------------------------------------------------------------------- */ + +#define REQ_TYPE_GET_STATUS 0x01 // same as _GET_STATS +#define REQ_TYPE_KEEP_ALIVE 0x02 +#define REQ_TYPE_GET_TELEMETRY_DATA 0x03 + +#define MAX_SIGN_DATA_LEN (8*1024) // 8K + +class MyMesh : public BaseChatMesh { +public: + MyMesh(mesh::Radio& radio, mesh::RNG& rng, mesh::RTCClock& rtc, SimpleMeshTables& tables); + + void begin(FILESYSTEM& fs, bool has_display); + void startInterface(BaseSerialInterface& serial); + void loadPrefsInt(const char* filename); + void savePrefs(); + + const char* getNodeName(); + NodePrefs* getNodePrefs(); + uint32_t getBLEPin(); + + void loop(); + void handleCmdFrame(size_t len); + bool advert(); + +protected: + float getAirtimeBudgetFactor() const override; + int getInterferenceThreshold() const override; + int calcRxDelay(float score, uint32_t air_time) const override; + + void logRxRaw(float snr, float rssi, const uint8_t raw[], int len) override; + bool isAutoAddEnabled() const override; + void onDiscoveredContact(ContactInfo& contact, bool is_new) override; + void onContactPathUpdated(const ContactInfo& contact) override; + bool processAck(const uint8_t *data) override; + void queueMessage(const ContactInfo& from, uint8_t txt_type, mesh::Packet* pkt, + uint32_t sender_timestamp, const uint8_t* extra, int extra_len, const char *text); + + void onMessageRecv(const ContactInfo& from, mesh::Packet* pkt, uint32_t sender_timestamp, const char *text) override; + void onCommandDataRecv(const ContactInfo& from, mesh::Packet* pkt, uint32_t sender_timestamp, const char *text) override; + void onSignedMessageRecv(const ContactInfo& from, mesh::Packet* pkt, uint32_t sender_timestamp, + const uint8_t *sender_prefix, const char *text) override; + void onChannelMessageRecv(const mesh::GroupChannel& channel, mesh::Packet* pkt, uint32_t timestamp, const char *text) override; + + uint8_t onContactRequest(const ContactInfo& contact, uint32_t sender_timestamp, const uint8_t* data, uint8_t len, uint8_t* reply) override; + void onContactResponse(const ContactInfo& contact, const uint8_t* data, uint8_t len) override; + void onRawDataRecv(mesh::Packet* packet) override; + void onTraceRecv(mesh::Packet* packet, uint32_t tag, uint32_t auth_code, uint8_t flags, const uint8_t* path_snrs, + const uint8_t* path_hashes, uint8_t path_len) override; + + uint32_t calcFloodTimeoutMillisFor(uint32_t pkt_airtime_millis) const override; + uint32_t calcDirectTimeoutMillisFor(uint32_t pkt_airtime_millis, uint8_t path_len) const override; + void onSendTimeout() override; + +private: + void writeOKFrame(); + void writeErrFrame(uint8_t err_code); + void writeDisabledFrame(); + void writeContactRespFrame(uint8_t code, const ContactInfo& contact); + void updateContactFromFrame(ContactInfo& contact, const uint8_t* frame, int len); + void addToOfflineQueue(const uint8_t frame[], int len); + int getFromOfflineQueue(uint8_t frame[]); + void loadMainIdentity(); + bool saveMainIdentity(const mesh::LocalIdentity& identity); + void loadContacts(); + void saveContacts(); + void loadChannels(); + void saveChannels(); + int getBlobByKey(const uint8_t key[], int key_len, uint8_t dest_buf[]) override; + bool putBlobByKey(const uint8_t key[], int key_len, const uint8_t src_buf[], int len) override; + +private: + FILESYSTEM* _fs; + IdentityStore* _identity_store; + NodePrefs _prefs; + uint32_t pending_login; + uint32_t pending_status; + uint32_t pending_telemetry; + BaseSerialInterface* _serial; + + ContactsIterator _iter; + uint32_t _iter_filter_since; + uint32_t _most_recent_lastmod; + uint32_t _active_ble_pin; + bool _iter_started; + uint8_t app_target_ver; + uint8_t* sign_data; + uint32_t sign_data_len; + unsigned long dirty_contacts_expiry; + + uint8_t cmd_frame[MAX_FRAME_SIZE + 1]; + uint8_t out_frame[MAX_FRAME_SIZE + 1]; + CayenneLPP telemetry; + + struct Frame { + uint8_t len; + uint8_t buf[MAX_FRAME_SIZE]; + }; + int offline_queue_len; + Frame offline_queue[OFFLINE_QUEUE_SIZE]; + + struct AckTableEntry { + unsigned long msg_sent; + uint32_t ack; + }; + #define EXPECTED_ACK_TABLE_SIZE 8 + AckTableEntry expected_ack_table[EXPECTED_ACK_TABLE_SIZE]; // circular table + int next_ack_idx; +}; + +extern StdRNG fast_rng; +extern SimpleMeshTables tables; +extern MyMesh the_mesh; +#ifdef DISPLAY_CLASS + extern UITask ui_task; +#endif +#endif // MYMESH_H \ No newline at end of file diff --git a/examples/companion_radio/UITask.cpp b/examples/companion_radio/UITask.cpp index 5ff5f1405..eabfd8f7c 100644 --- a/examples/companion_radio/UITask.cpp +++ b/examples/companion_radio/UITask.cpp @@ -2,6 +2,7 @@ #include #include #include "NodePrefs.h" +#include "MyMesh.h" #define AUTO_OFF_MILLIS 15000 // 15 seconds #define BOOT_SCREEN_MILLIS 4000 // 4 seconds @@ -340,8 +341,14 @@ void UITask::handleButtonShortPress() { } void UITask::handleButtonDoublePress() { - MESH_DEBUG_PRINTLN("UITask: double press triggered"); - // Not implemented. TODO: possibly send an advert here? + MESH_DEBUG_PRINTLN("UITask: double press triggered, sending advert"); + // ADVERT + if(the_mesh.advert()) { + MESH_DEBUG_PRINTLN("Advert sent!"); + } + else { + MESH_DEBUG_PRINTLN("Advert failed!"); + } } void UITask::handleButtonTriplePress() { diff --git a/examples/companion_radio/UITask.h b/examples/companion_radio/UITask.h index acf5237ea..6d7e1eb34 100644 --- a/examples/companion_radio/UITask.h +++ b/examples/companion_radio/UITask.h @@ -1,4 +1,5 @@ -#pragma once +#ifndef UI_TASK_H +#define UI_TASK_H #include #include @@ -72,3 +73,4 @@ class UITask { void shutdown(bool restart = false); void loop(); }; +#endif //UI_TASK_H \ No newline at end of file diff --git a/examples/companion_radio/main.cpp b/examples/companion_radio/main.cpp index 30a1c9ccb..6677d49b5 100644 --- a/examples/companion_radio/main.cpp +++ b/examples/companion_radio/main.cpp @@ -1,71 +1,6 @@ #include // needed for PlatformIO #include - -#if defined(NRF52_PLATFORM) || defined(STM32_PLATFORM) - #include -#elif defined(RP2040_PLATFORM) - #include -#elif defined(ESP32) - #include -#endif - -#include -#include -#include -#include -#include -#include "NodePrefs.h" -#include -#include - -/* ---------------------------------- CONFIGURATION ------------------------------------- */ - -#ifndef LORA_FREQ - #define LORA_FREQ 915.0 -#endif -#ifndef LORA_BW - #define LORA_BW 250 -#endif -#ifndef LORA_SF - #define LORA_SF 10 -#endif -#ifndef LORA_CR - #define LORA_CR 5 -#endif -#ifndef LORA_TX_POWER - #define LORA_TX_POWER 20 -#endif -#ifndef MAX_LORA_TX_POWER - #define MAX_LORA_TX_POWER LORA_TX_POWER -#endif - -#ifndef MAX_CONTACTS - #define MAX_CONTACTS 100 -#endif - -#ifndef OFFLINE_QUEUE_SIZE - #define OFFLINE_QUEUE_SIZE 16 -#endif - -#ifndef BLE_NAME_PREFIX - #define BLE_NAME_PREFIX "MeshCore-" -#endif - -#include - -#define SEND_TIMEOUT_BASE_MILLIS 500 -#define FLOOD_SEND_TIMEOUT_FACTOR 16.0f -#define DIRECT_SEND_PERHOP_FACTOR 6.0f -#define DIRECT_SEND_PERHOP_EXTRA_MILLIS 250 -#define LAZY_CONTACTS_WRITE_DELAY 5000 - -#define PUBLIC_GROUP_PSK "izOH6cXN6mrJ5e26oRXNcg==" - -#ifdef DISPLAY_CLASS - #include "UITask.h" - - static UITask ui_task(&board); -#endif +#include "MyMesh.h" // Believe it or not, this std C function is busted on some platforms! static uint32_t _atoi(const char* sp) { @@ -77,1518 +12,13 @@ static uint32_t _atoi(const char* sp) { return n; } -/*------------ Frame Protocol --------------*/ - -#define FIRMWARE_VER_CODE 5 - -#ifndef FIRMWARE_BUILD_DATE - #define FIRMWARE_BUILD_DATE "24 May 2025" -#endif - -#ifndef FIRMWARE_VERSION - #define FIRMWARE_VERSION "v1.6.2" -#endif - -#define CMD_APP_START 1 -#define CMD_SEND_TXT_MSG 2 -#define CMD_SEND_CHANNEL_TXT_MSG 3 -#define CMD_GET_CONTACTS 4 // with optional 'since' (for efficient sync) -#define CMD_GET_DEVICE_TIME 5 -#define CMD_SET_DEVICE_TIME 6 -#define CMD_SEND_SELF_ADVERT 7 -#define CMD_SET_ADVERT_NAME 8 -#define CMD_ADD_UPDATE_CONTACT 9 -#define CMD_SYNC_NEXT_MESSAGE 10 -#define CMD_SET_RADIO_PARAMS 11 -#define CMD_SET_RADIO_TX_POWER 12 -#define CMD_RESET_PATH 13 -#define CMD_SET_ADVERT_LATLON 14 -#define CMD_REMOVE_CONTACT 15 -#define CMD_SHARE_CONTACT 16 -#define CMD_EXPORT_CONTACT 17 -#define CMD_IMPORT_CONTACT 18 -#define CMD_REBOOT 19 -#define CMD_GET_BATTERY_VOLTAGE 20 -#define CMD_SET_TUNING_PARAMS 21 -#define CMD_DEVICE_QEURY 22 -#define CMD_EXPORT_PRIVATE_KEY 23 -#define CMD_IMPORT_PRIVATE_KEY 24 -#define CMD_SEND_RAW_DATA 25 -#define CMD_SEND_LOGIN 26 -#define CMD_SEND_STATUS_REQ 27 -#define CMD_HAS_CONNECTION 28 -#define CMD_LOGOUT 29 // 'Disconnect' -#define CMD_GET_CONTACT_BY_KEY 30 -#define CMD_GET_CHANNEL 31 -#define CMD_SET_CHANNEL 32 -#define CMD_SIGN_START 33 -#define CMD_SIGN_DATA 34 -#define CMD_SIGN_FINISH 35 -#define CMD_SEND_TRACE_PATH 36 -#define CMD_SET_DEVICE_PIN 37 -#define CMD_SET_OTHER_PARAMS 38 -#define CMD_SEND_TELEMETRY_REQ 39 -#define CMD_GET_CUSTOM_VARS 40 -#define CMD_SET_CUSTOM_VAR 41 - -#define RESP_CODE_OK 0 -#define RESP_CODE_ERR 1 -#define RESP_CODE_CONTACTS_START 2 // first reply to CMD_GET_CONTACTS -#define RESP_CODE_CONTACT 3 // multiple of these (after CMD_GET_CONTACTS) -#define RESP_CODE_END_OF_CONTACTS 4 // last reply to CMD_GET_CONTACTS -#define RESP_CODE_SELF_INFO 5 // reply to CMD_APP_START -#define RESP_CODE_SENT 6 // reply to CMD_SEND_TXT_MSG -#define RESP_CODE_CONTACT_MSG_RECV 7 // a reply to CMD_SYNC_NEXT_MESSAGE (ver < 3) -#define RESP_CODE_CHANNEL_MSG_RECV 8 // a reply to CMD_SYNC_NEXT_MESSAGE (ver < 3) -#define RESP_CODE_CURR_TIME 9 // a reply to CMD_GET_DEVICE_TIME -#define RESP_CODE_NO_MORE_MESSAGES 10 // a reply to CMD_SYNC_NEXT_MESSAGE -#define RESP_CODE_EXPORT_CONTACT 11 -#define RESP_CODE_BATTERY_VOLTAGE 12 // a reply to a CMD_GET_BATTERY_VOLTAGE -#define RESP_CODE_DEVICE_INFO 13 // a reply to CMD_DEVICE_QEURY -#define RESP_CODE_PRIVATE_KEY 14 // a reply to CMD_EXPORT_PRIVATE_KEY -#define RESP_CODE_DISABLED 15 -#define RESP_CODE_CONTACT_MSG_RECV_V3 16 // a reply to CMD_SYNC_NEXT_MESSAGE (ver >= 3) -#define RESP_CODE_CHANNEL_MSG_RECV_V3 17 // a reply to CMD_SYNC_NEXT_MESSAGE (ver >= 3) -#define RESP_CODE_CHANNEL_INFO 18 // a reply to CMD_GET_CHANNEL -#define RESP_CODE_SIGN_START 19 -#define RESP_CODE_SIGNATURE 20 -#define RESP_CODE_CUSTOM_VARS 21 - -// these are _pushed_ to client app at any time -#define PUSH_CODE_ADVERT 0x80 -#define PUSH_CODE_PATH_UPDATED 0x81 -#define PUSH_CODE_SEND_CONFIRMED 0x82 -#define PUSH_CODE_MSG_WAITING 0x83 -#define PUSH_CODE_RAW_DATA 0x84 -#define PUSH_CODE_LOGIN_SUCCESS 0x85 -#define PUSH_CODE_LOGIN_FAIL 0x86 -#define PUSH_CODE_STATUS_RESPONSE 0x87 -#define PUSH_CODE_LOG_RX_DATA 0x88 -#define PUSH_CODE_TRACE_DATA 0x89 -#define PUSH_CODE_NEW_ADVERT 0x8A -#define PUSH_CODE_TELEMETRY_RESPONSE 0x8B - -#define ERR_CODE_UNSUPPORTED_CMD 1 -#define ERR_CODE_NOT_FOUND 2 -#define ERR_CODE_TABLE_FULL 3 -#define ERR_CODE_BAD_STATE 4 -#define ERR_CODE_FILE_IO_ERROR 5 -#define ERR_CODE_ILLEGAL_ARG 6 - -/* -------------------------------------------------------------------------------------- */ - -#define REQ_TYPE_GET_STATUS 0x01 // same as _GET_STATS -#define REQ_TYPE_KEEP_ALIVE 0x02 -#define REQ_TYPE_GET_TELEMETRY_DATA 0x03 - -#define MAX_SIGN_DATA_LEN (8*1024) // 8K - -class MyMesh : public BaseChatMesh { - FILESYSTEM* _fs; - IdentityStore* _identity_store; - NodePrefs _prefs; - uint32_t pending_login; - uint32_t pending_status; - uint32_t pending_telemetry; - BaseSerialInterface* _serial; - ContactsIterator _iter; - uint32_t _iter_filter_since; - uint32_t _most_recent_lastmod; - uint32_t _active_ble_pin; - bool _iter_started; - uint8_t app_target_ver; - uint8_t* sign_data; - uint32_t sign_data_len; - unsigned long dirty_contacts_expiry; - uint8_t cmd_frame[MAX_FRAME_SIZE+1]; - uint8_t out_frame[MAX_FRAME_SIZE+1]; - CayenneLPP telemetry; - - struct Frame { - uint8_t len; - uint8_t buf[MAX_FRAME_SIZE]; - }; - int offline_queue_len; - Frame offline_queue[OFFLINE_QUEUE_SIZE]; - - struct AckTableEntry { - unsigned long msg_sent; - uint32_t ack; - }; - #define EXPECTED_ACK_TABLE_SIZE 8 - AckTableEntry expected_ack_table[EXPECTED_ACK_TABLE_SIZE]; // circular table - int next_ack_idx; - - void loadMainIdentity() { - if (!_identity_store->load("_main", self_id)) { - self_id = radio_new_identity(); // create new random identity - int count = 0; - while (count < 10 && (self_id.pub_key[0] == 0x00 || self_id.pub_key[0] == 0xFF)) { // reserved id hashes - self_id = radio_new_identity(); count++; - } - saveMainIdentity(self_id); - } - } - - bool saveMainIdentity(const mesh::LocalIdentity& identity) { - return _identity_store->save("_main", identity); - } - - void loadContacts() { - if (_fs->exists("/contacts3")) { - #if defined(RP2040_PLATFORM) - File file = _fs->open("/contacts3", "r"); - #else - File file = _fs->open("/contacts3"); - #endif - if (file) { - bool full = false; - while (!full) { - ContactInfo c; - uint8_t pub_key[32]; - uint8_t unused; - - bool success = (file.read(pub_key, 32) == 32); - success = success && (file.read((uint8_t *) &c.name, 32) == 32); - success = success && (file.read(&c.type, 1) == 1); - success = success && (file.read(&c.flags, 1) == 1); - success = success && (file.read(&unused, 1) == 1); - success = success && (file.read((uint8_t *) &c.sync_since, 4) == 4); // was 'reserved' - success = success && (file.read((uint8_t *) &c.out_path_len, 1) == 1); - success = success && (file.read((uint8_t *) &c.last_advert_timestamp, 4) == 4); - success = success && (file.read(c.out_path, 64) == 64); - success = success && (file.read((uint8_t *) &c.lastmod, 4) == 4); - success = success && (file.read((uint8_t *) &c.gps_lat, 4) == 4); - success = success && (file.read((uint8_t *) &c.gps_lon, 4) == 4); - - if (!success) break; // EOF - - c.id = mesh::Identity(pub_key); - if (!addContact(c)) full = true; - } - file.close(); - } - } - } - - void saveContacts() { -#if defined(NRF52_PLATFORM) || defined(STM32_PLATFORM) - _fs->remove("/contacts3"); - File file = _fs->open("/contacts3", FILE_O_WRITE); -#elif defined(RP2040_PLATFORM) - File file = _fs->open("/contacts3", "w"); -#else - File file = _fs->open("/contacts3", "w", true); -#endif - if (file) { - ContactsIterator iter; - ContactInfo c; - uint8_t unused = 0; - - while (iter.hasNext(this, c)) { - bool success = (file.write(c.id.pub_key, 32) == 32); - success = success && (file.write((uint8_t *) &c.name, 32) == 32); - success = success && (file.write(&c.type, 1) == 1); - success = success && (file.write(&c.flags, 1) == 1); - success = success && (file.write(&unused, 1) == 1); - success = success && (file.write((uint8_t *) &c.sync_since, 4) == 4); - success = success && (file.write((uint8_t *) &c.out_path_len, 1) == 1); - success = success && (file.write((uint8_t *) &c.last_advert_timestamp, 4) == 4); - success = success && (file.write(c.out_path, 64) == 64); - success = success && (file.write((uint8_t *) &c.lastmod, 4) == 4); - success = success && (file.write((uint8_t *) &c.gps_lat, 4) == 4); - success = success && (file.write((uint8_t *) &c.gps_lon, 4) == 4); - - if (!success) break; // write failed - } - file.close(); - } - } - - void loadChannels() { - if (_fs->exists("/channels2")) { - #if defined(RP2040_PLATFORM) - File file = _fs->open("/channels2", "r"); - #else - File file = _fs->open("/channels2"); - #endif - if (file) { - bool full = false; - uint8_t channel_idx = 0; - while (!full) { - ChannelDetails ch; - uint8_t unused[4]; - - bool success = (file.read(unused, 4) == 4); - success = success && (file.read((uint8_t *) ch.name, 32) == 32); - success = success && (file.read((uint8_t *) ch.channel.secret, 32) == 32); - - if (!success) break; // EOF - - if (setChannel(channel_idx, ch)) { - channel_idx++; - } else { - full = true; - } - } - file.close(); - } - } - } - - void saveChannels() { - #if defined(NRF52_PLATFORM) || defined(STM32_PLATFORM) - _fs->remove("/channels2"); - File file = _fs->open("/channels2", FILE_O_WRITE); - #elif defined(RP2040_PLATFORM) - File file = _fs->open("/channels2", "w"); - #else - File file = _fs->open("/channels2", "w", true); - #endif - if (file) { - uint8_t channel_idx = 0; - ChannelDetails ch; - uint8_t unused[4]; - memset(unused, 0, 4); - - while (getChannel(channel_idx, ch)) { - bool success = (file.write(unused, 4) == 4); - success = success && (file.write((uint8_t *) ch.name, 32) == 32); - success = success && (file.write((uint8_t *) ch.channel.secret, 32) == 32); - - if (!success) break; // write failed - channel_idx++; - } - file.close(); - } - } - - int getBlobByKey(const uint8_t key[], int key_len, uint8_t dest_buf[]) override { - char path[64]; - char fname[18]; - - if (key_len > 8) key_len = 8; // just use first 8 bytes (prefix) - mesh::Utils::toHex(fname, key, key_len); - sprintf(path, "/bl/%s", fname); - - if (_fs->exists(path)) { - #if defined(RP2040_PLATFORM) - File f = _fs->open(path, "r"); - #else - File f = _fs->open(path); - #endif - if (f) { - int len = f.read(dest_buf, 255); // currently MAX 255 byte blob len supported!! - f.close(); - return len; - } - } - return 0; // not found - } - - bool putBlobByKey(const uint8_t key[], int key_len, const uint8_t src_buf[], int len) override { - char path[64]; - char fname[18]; - - if (key_len > 8) key_len = 8; // just use first 8 bytes (prefix) - mesh::Utils::toHex(fname, key, key_len); - sprintf(path, "/bl/%s", fname); - - #if defined(NRF52_PLATFORM) || defined(STM32_PLATFORM) - _fs->remove(path); - File f = _fs->open(path, FILE_O_WRITE); - #elif defined(RP2040_PLATFORM) - File f = _fs->open(path, "w"); - #else - File f = _fs->open(path, "w", true); - #endif - if (f) { - int n = f.write(src_buf, len); - f.close(); - if (n == len) return true; // success! - - _fs->remove(path); // blob was only partially written! - } - return false; // error - } - - void writeOKFrame() { - uint8_t buf[1]; - buf[0] = RESP_CODE_OK; - _serial->writeFrame(buf, 1); - } - void writeErrFrame(uint8_t err_code) { - uint8_t buf[2]; - buf[0] = RESP_CODE_ERR; - buf[1] = err_code; - _serial->writeFrame(buf, 2); - } - - void writeDisabledFrame() { - uint8_t buf[1]; - buf[0] = RESP_CODE_DISABLED; - _serial->writeFrame(buf, 1); - } - - void writeContactRespFrame(uint8_t code, const ContactInfo& contact) { - int i = 0; - out_frame[i++] = code; - memcpy(&out_frame[i], contact.id.pub_key, PUB_KEY_SIZE); i += PUB_KEY_SIZE; - out_frame[i++] = contact.type; - out_frame[i++] = contact.flags; - out_frame[i++] = contact.out_path_len; - memcpy(&out_frame[i], contact.out_path, MAX_PATH_SIZE); i += MAX_PATH_SIZE; - StrHelper::strzcpy((char *) &out_frame[i], contact.name, 32); i += 32; - memcpy(&out_frame[i], &contact.last_advert_timestamp, 4); i += 4; - memcpy(&out_frame[i], &contact.gps_lat, 4); i += 4; - memcpy(&out_frame[i], &contact.gps_lon, 4); i += 4; - memcpy(&out_frame[i], &contact.lastmod, 4); i += 4; - _serial->writeFrame(out_frame, i); - } - - void updateContactFromFrame(ContactInfo& contact, const uint8_t* frame, int len) { - int i = 0; - uint8_t code = frame[i++]; // eg. CMD_ADD_UPDATE_CONTACT - memcpy(contact.id.pub_key, &frame[i], PUB_KEY_SIZE); i += PUB_KEY_SIZE; - contact.type = frame[i++]; - contact.flags = frame[i++]; - contact.out_path_len = frame[i++]; - memcpy(contact.out_path, &frame[i], MAX_PATH_SIZE); i += MAX_PATH_SIZE; - memcpy(contact.name, &frame[i], 32); i += 32; - memcpy(&contact.last_advert_timestamp, &frame[i], 4); i += 4; - if (i + 8 >= len) { // optional fields - memcpy(&contact.gps_lat, &frame[i], 4); i += 4; - memcpy(&contact.gps_lon, &frame[i], 4); i += 4; - } - } - - void addToOfflineQueue(const uint8_t frame[], int len) { - if (offline_queue_len >= OFFLINE_QUEUE_SIZE) { - MESH_DEBUG_PRINTLN("ERROR: offline_queue is full!"); - } else { - offline_queue[offline_queue_len].len = len; - memcpy(offline_queue[offline_queue_len].buf, frame, len); - offline_queue_len++; - } - } - int getFromOfflineQueue(uint8_t frame[]) { - if (offline_queue_len > 0) { // check offline queue - size_t len = offline_queue[0].len; // take from top of queue - memcpy(frame, offline_queue[0].buf, len); - - offline_queue_len--; - for (int i = 0; i < offline_queue_len; i++) { // delete top item from queue - offline_queue[i] = offline_queue[i + 1]; - } - return len; - } - return 0; // queue is empty - } - -protected: - float getAirtimeBudgetFactor() const override { - return _prefs.airtime_factor; - } - - int getInterferenceThreshold() const override { - return 14; // hard-coded for now - } - - int calcRxDelay(float score, uint32_t air_time) const override { - if (_prefs.rx_delay_base <= 0.0f) return 0; - return (int) ((pow(_prefs.rx_delay_base, 0.85f - score) - 1.0) * air_time); - } - - void logRxRaw(float snr, float rssi, const uint8_t raw[], int len) override { - if (_serial->isConnected() && len+3 <= MAX_FRAME_SIZE) { - int i = 0; - out_frame[i++] = PUSH_CODE_LOG_RX_DATA; - out_frame[i++] = (int8_t)(snr * 4); - out_frame[i++] = (int8_t)(rssi); - memcpy(&out_frame[i], raw, len); i += len; - - _serial->writeFrame(out_frame, i); - } - } - - bool isAutoAddEnabled() const override { - return (_prefs.manual_add_contacts & 1) == 0; - } - - void onDiscoveredContact(ContactInfo& contact, bool is_new) override { - if (_serial->isConnected()) { - if (!isAutoAddEnabled() && is_new) { - writeContactRespFrame(PUSH_CODE_NEW_ADVERT, contact); - } else { - out_frame[0] = PUSH_CODE_ADVERT; - memcpy(&out_frame[1], contact.id.pub_key, PUB_KEY_SIZE); - _serial->writeFrame(out_frame, 1 + PUB_KEY_SIZE); - } - } else { - #ifdef DISPLAY_CLASS - ui_task.soundBuzzer(UIEventType::newContactMessage); - #endif - } - - dirty_contacts_expiry = futureMillis(LAZY_CONTACTS_WRITE_DELAY); - } - - void onContactPathUpdated(const ContactInfo& contact) override { - out_frame[0] = PUSH_CODE_PATH_UPDATED; - memcpy(&out_frame[1], contact.id.pub_key, PUB_KEY_SIZE); - _serial->writeFrame(out_frame, 1 + PUB_KEY_SIZE); // NOTE: app may not be connected - - dirty_contacts_expiry = futureMillis(LAZY_CONTACTS_WRITE_DELAY); - } - - bool processAck(const uint8_t *data) override { - // see if matches any in a table - for (int i = 0; i < EXPECTED_ACK_TABLE_SIZE; i++) { - if (memcmp(data, &expected_ack_table[i].ack, 4) == 0) { // got an ACK from recipient - out_frame[0] = PUSH_CODE_SEND_CONFIRMED; - memcpy(&out_frame[1], data, 4); - uint32_t trip_time = _ms->getMillis() - expected_ack_table[i].msg_sent; - memcpy(&out_frame[5], &trip_time, 4); - _serial->writeFrame(out_frame, 9); - - // NOTE: the same ACK can be received multiple times! - expected_ack_table[i].ack = 0; // clear expected hash, now that we have received ACK - return true; - } - } - return checkConnectionsAck(data); - } - - void queueMessage(const ContactInfo& from, uint8_t txt_type, mesh::Packet* pkt, uint32_t sender_timestamp, const uint8_t* extra, int extra_len, const char *text) { - int i = 0; - if (app_target_ver >= 3) { - out_frame[i++] = RESP_CODE_CONTACT_MSG_RECV_V3; - out_frame[i++] = (int8_t)(pkt->getSNR() * 4); - out_frame[i++] = 0; // reserved1 - out_frame[i++] = 0; // reserved2 - } else { - out_frame[i++] = RESP_CODE_CONTACT_MSG_RECV; - } - memcpy(&out_frame[i], from.id.pub_key, 6); i += 6; // just 6-byte prefix - uint8_t path_len = out_frame[i++] = pkt->isRouteFlood() ? pkt->path_len : 0xFF; - out_frame[i++] = txt_type; - memcpy(&out_frame[i], &sender_timestamp, 4); i += 4; - if (extra_len > 0) { - memcpy(&out_frame[i], extra, extra_len); i += extra_len; - } - int tlen = strlen(text); // TODO: UTF-8 ?? - if (i + tlen > MAX_FRAME_SIZE) { - tlen = MAX_FRAME_SIZE - i; - } - memcpy(&out_frame[i], text, tlen); i += tlen; - addToOfflineQueue(out_frame, i); - - if (_serial->isConnected()) { - uint8_t frame[1]; - frame[0] = PUSH_CODE_MSG_WAITING; // send push 'tickle' - _serial->writeFrame(frame, 1); - } else { - #ifdef DISPLAY_CLASS - ui_task.soundBuzzer(UIEventType::contactMessage); - #endif - } - #ifdef DISPLAY_CLASS - ui_task.newMsg(path_len, from.name, text, offline_queue_len); - #endif - } - - void onMessageRecv(const ContactInfo& from, mesh::Packet* pkt, uint32_t sender_timestamp, const char *text) override { - markConnectionActive(from); // in case this is from a server, and we have a connection - queueMessage(from, TXT_TYPE_PLAIN, pkt, sender_timestamp, NULL, 0, text); - } - - void onCommandDataRecv(const ContactInfo& from, mesh::Packet* pkt, uint32_t sender_timestamp, const char *text) override { - markConnectionActive(from); // in case this is from a server, and we have a connection - queueMessage(from, TXT_TYPE_CLI_DATA, pkt, sender_timestamp, NULL, 0, text); - } - - void onSignedMessageRecv(const ContactInfo& from, mesh::Packet* pkt, uint32_t sender_timestamp, const uint8_t *sender_prefix, const char *text) override { - markConnectionActive(from); - // from.sync_since change needs to be persisted - dirty_contacts_expiry = futureMillis(LAZY_CONTACTS_WRITE_DELAY); - queueMessage(from, TXT_TYPE_SIGNED_PLAIN, pkt, sender_timestamp, sender_prefix, 4, text); - } - - void onChannelMessageRecv(const mesh::GroupChannel& channel, mesh::Packet* pkt, uint32_t timestamp, const char *text) override { - int i = 0; - if (app_target_ver >= 3) { - out_frame[i++] = RESP_CODE_CHANNEL_MSG_RECV_V3; - out_frame[i++] = (int8_t)(pkt->getSNR() * 4); - out_frame[i++] = 0; // reserved1 - out_frame[i++] = 0; // reserved2 - } else { - out_frame[i++] = RESP_CODE_CHANNEL_MSG_RECV; - } - - out_frame[i++] = findChannelIdx(channel); - uint8_t path_len = out_frame[i++] = pkt->isRouteFlood() ? pkt->path_len : 0xFF; - - out_frame[i++] = TXT_TYPE_PLAIN; - memcpy(&out_frame[i], ×tamp, 4); i += 4; - int tlen = strlen(text); // TODO: UTF-8 ?? - if (i + tlen > MAX_FRAME_SIZE) { - tlen = MAX_FRAME_SIZE - i; - } - memcpy(&out_frame[i], text, tlen); i += tlen; - addToOfflineQueue(out_frame, i); - - if (_serial->isConnected()) { - uint8_t frame[1]; - frame[0] = PUSH_CODE_MSG_WAITING; // send push 'tickle' - _serial->writeFrame(frame, 1); - } else { - #ifdef DISPLAY_CLASS - ui_task.soundBuzzer(UIEventType::channelMessage); - #endif - } - #ifdef DISPLAY_CLASS - ui_task.newMsg(path_len, "Public", text, offline_queue_len); - #endif - } - - uint8_t onContactRequest(const ContactInfo& contact, uint32_t sender_timestamp, const uint8_t* data, uint8_t len, uint8_t* reply) override { - if (data[0] == REQ_TYPE_GET_TELEMETRY_DATA) { - uint8_t permissions = 0; - uint8_t cp = contact.flags >> 1; // LSB used as 'favourite' bit (so only use upper bits) - - if (_prefs.telemetry_mode_base == TELEM_MODE_ALLOW_ALL) { - permissions = TELEM_PERM_BASE; - } else if (_prefs.telemetry_mode_base == TELEM_MODE_ALLOW_FLAGS) { - permissions = cp & TELEM_PERM_BASE; - } - - if (_prefs.telemetry_mode_loc == TELEM_MODE_ALLOW_ALL) { - permissions |= TELEM_PERM_LOCATION; - } else if (_prefs.telemetry_mode_loc == TELEM_MODE_ALLOW_FLAGS) { - permissions |= cp & TELEM_PERM_LOCATION; - } - - if (_prefs.telemetry_mode_env == TELEM_MODE_ALLOW_ALL) { - permissions |= TELEM_PERM_ENVIRONMENT; - } else if (_prefs.telemetry_mode_env == TELEM_MODE_ALLOW_FLAGS) { - permissions |= cp & TELEM_PERM_ENVIRONMENT; - } - - if (permissions & TELEM_PERM_BASE) { // only respond if base permission bit is set - telemetry.reset(); - telemetry.addVoltage(TELEM_CHANNEL_SELF, (float)board.getBattMilliVolts() / 1000.0f); - // query other sensors -- target specific - sensors.querySensors(permissions, telemetry); - - memcpy(reply, &sender_timestamp, 4); // reflect sender_timestamp back in response packet (kind of like a 'tag') - - uint8_t tlen = telemetry.getSize(); - memcpy(&reply[4], telemetry.getBuffer(), tlen); - return 4 + tlen; - } - } - return 0; // unknown - } - - void onContactResponse(const ContactInfo& contact, const uint8_t* data, uint8_t len) override { - uint32_t tag; - memcpy(&tag, data, 4); - - if (pending_login && memcmp(&pending_login, contact.id.pub_key, 4) == 0) { // check for login response - // yes, is response to pending sendLogin() - pending_login = 0; - - int i = 0; - if (memcmp(&data[4], "OK", 2) == 0) { // legacy Repeater login OK response - out_frame[i++] = PUSH_CODE_LOGIN_SUCCESS; - out_frame[i++] = 0; // legacy: is_admin = false - memcpy(&out_frame[i], contact.id.pub_key, 6); i += 6; // pub_key_prefix - } else if (data[4] == RESP_SERVER_LOGIN_OK) { // new login response - uint16_t keep_alive_secs = ((uint16_t)data[5]) * 16; - if (keep_alive_secs > 0) { - startConnection(contact, keep_alive_secs); - } - out_frame[i++] = PUSH_CODE_LOGIN_SUCCESS; - out_frame[i++] = data[6]; // permissions (eg. is_admin) - memcpy(&out_frame[i], contact.id.pub_key, 6); i += 6; // pub_key_prefix - memcpy(&out_frame[i], &tag, 4); i += 4; // NEW: include server timestamp - } else { - out_frame[i++] = PUSH_CODE_LOGIN_FAIL; - out_frame[i++] = 0; // reserved - memcpy(&out_frame[i], contact.id.pub_key, 6); i += 6; // pub_key_prefix - } - _serial->writeFrame(out_frame, i); - } else if (len > 4 && // check for status response - pending_status && memcmp(&pending_status, contact.id.pub_key, 4) == 0 // legacy matching scheme - // FUTURE: tag == pending_status - ) { - pending_status = 0; - - int i = 0; - out_frame[i++] = PUSH_CODE_STATUS_RESPONSE; - out_frame[i++] = 0; // reserved - memcpy(&out_frame[i], contact.id.pub_key, 6); i += 6; // pub_key_prefix - memcpy(&out_frame[i], &data[4], len - 4); i += (len - 4); - _serial->writeFrame(out_frame, i); - } else if (len > 4 && tag == pending_telemetry) { // check for telemetry response - pending_telemetry = 0; - - int i = 0; - out_frame[i++] = PUSH_CODE_TELEMETRY_RESPONSE; - out_frame[i++] = 0; // reserved - memcpy(&out_frame[i], contact.id.pub_key, 6); i += 6; // pub_key_prefix - memcpy(&out_frame[i], &data[4], len - 4); i += (len - 4); - _serial->writeFrame(out_frame, i); - } - } - - void onRawDataRecv(mesh::Packet* packet) override { - if (packet->payload_len + 4 > sizeof(out_frame)) { - MESH_DEBUG_PRINTLN("onRawDataRecv(), payload_len too long: %d", packet->payload_len); - return; - } - int i = 0; - out_frame[i++] = PUSH_CODE_RAW_DATA; - out_frame[i++] = (int8_t)(_radio->getLastSNR() * 4); - out_frame[i++] = (int8_t)(_radio->getLastRSSI()); - out_frame[i++] = 0xFF; // reserved (possibly path_len in future) - memcpy(&out_frame[i], packet->payload, packet->payload_len); i += packet->payload_len; - - if (_serial->isConnected()) { - _serial->writeFrame(out_frame, i); - } else { - MESH_DEBUG_PRINTLN("onRawDataRecv(), data received while app offline"); - } - } - - void onTraceRecv(mesh::Packet* packet, uint32_t tag, uint32_t auth_code, uint8_t flags, const uint8_t* path_snrs, const uint8_t* path_hashes, uint8_t path_len) override { - int i = 0; - out_frame[i++] = PUSH_CODE_TRACE_DATA; - out_frame[i++] = 0; // reserved - out_frame[i++] = path_len; - out_frame[i++] = flags; - memcpy(&out_frame[i], &tag, 4); i += 4; - memcpy(&out_frame[i], &auth_code, 4); i += 4; - memcpy(&out_frame[i], path_hashes, path_len); i += path_len; - memcpy(&out_frame[i], path_snrs, path_len); i += path_len; - out_frame[i++] = (int8_t)(packet->getSNR() * 4); // extra/final SNR (to this node) - - if (_serial->isConnected()) { - _serial->writeFrame(out_frame, i); - } else { - MESH_DEBUG_PRINTLN("onTraceRecv(), data received while app offline"); - } - } - - uint32_t calcFloodTimeoutMillisFor(uint32_t pkt_airtime_millis) const override { - return SEND_TIMEOUT_BASE_MILLIS + (FLOOD_SEND_TIMEOUT_FACTOR * pkt_airtime_millis); - } - uint32_t calcDirectTimeoutMillisFor(uint32_t pkt_airtime_millis, uint8_t path_len) const override { - return SEND_TIMEOUT_BASE_MILLIS + - ( (pkt_airtime_millis*DIRECT_SEND_PERHOP_FACTOR + DIRECT_SEND_PERHOP_EXTRA_MILLIS) * (path_len + 1)); - } - - void onSendTimeout() override { - } - -public: - - MyMesh(mesh::Radio& radio, mesh::RNG& rng, mesh::RTCClock& rtc, SimpleMeshTables& tables) - : BaseChatMesh(radio, *new ArduinoMillis(), rng, rtc, *new StaticPoolPacketManager(16), tables), _serial(NULL), - telemetry(MAX_PACKET_PAYLOAD - 4) - { - _iter_started = false; - offline_queue_len = 0; - app_target_ver = 0; - _identity_store = NULL; - pending_login = pending_status = pending_telemetry = 0; - next_ack_idx = 0; - sign_data = NULL; - dirty_contacts_expiry = 0; - - // defaults - memset(&_prefs, 0, sizeof(_prefs)); - _prefs.airtime_factor = 1.0; // one half - strcpy(_prefs.node_name, "NONAME"); - _prefs.freq = LORA_FREQ; - _prefs.sf = LORA_SF; - _prefs.bw = LORA_BW; - _prefs.cr = LORA_CR; - _prefs.tx_power_dbm = LORA_TX_POWER; - //_prefs.rx_delay_base = 10.0f; enable once new algo fixed - } - - void loadPrefsInt(const char* filename) { -#if defined(RP2040_PLATFORM) - File file = _fs->open(filename, "r"); -#else - File file = _fs->open(filename); -#endif - if (file) { - uint8_t pad[8]; - - file.read((uint8_t *) &_prefs.airtime_factor, sizeof(float)); // 0 - file.read((uint8_t *) _prefs.node_name, sizeof(_prefs.node_name)); // 4 - file.read(pad, 4); // 36 - file.read((uint8_t *) &sensors.node_lat, sizeof(sensors.node_lat)); // 40 - file.read((uint8_t *) &sensors.node_lon, sizeof(sensors.node_lon)); // 48 - file.read((uint8_t *) &_prefs.freq, sizeof(_prefs.freq)); // 56 - file.read((uint8_t *) &_prefs.sf, sizeof(_prefs.sf)); // 60 - file.read((uint8_t *) &_prefs.cr, sizeof(_prefs.cr)); // 61 - file.read((uint8_t *) &_prefs.reserved1, sizeof(_prefs.reserved1)); // 62 - file.read((uint8_t *) &_prefs.manual_add_contacts, sizeof(_prefs.manual_add_contacts)); // 63 - file.read((uint8_t *) &_prefs.bw, sizeof(_prefs.bw)); // 64 - file.read((uint8_t *) &_prefs.tx_power_dbm, sizeof(_prefs.tx_power_dbm)); // 68 - file.read((uint8_t *) &_prefs.telemetry_mode_base, sizeof(_prefs.telemetry_mode_base)); // 69 - file.read((uint8_t *) &_prefs.telemetry_mode_loc, sizeof(_prefs.telemetry_mode_loc)); // 70 - file.read((uint8_t *) &_prefs.telemetry_mode_env, sizeof(_prefs.telemetry_mode_env)); // 71 - file.read((uint8_t *) &_prefs.rx_delay_base, sizeof(_prefs.rx_delay_base)); // 72 - file.read(pad, 4); // 76 - file.read((uint8_t *) &_prefs.ble_pin, sizeof(_prefs.ble_pin)); // 80 - - // sanitise bad pref values - _prefs.rx_delay_base = constrain(_prefs.rx_delay_base, 0, 20.0f); - _prefs.airtime_factor = constrain(_prefs.airtime_factor, 0, 9.0f); - _prefs.freq = constrain(_prefs.freq, 400.0f, 2500.0f); - _prefs.bw = constrain(_prefs.bw, 62.5f, 500.0f); - _prefs.sf = constrain(_prefs.sf, 7, 12); - _prefs.cr = constrain(_prefs.cr, 5, 8); - _prefs.tx_power_dbm = constrain(_prefs.tx_power_dbm, 1, MAX_LORA_TX_POWER); - - file.close(); - } - } - - void begin(FILESYSTEM& fs, bool has_display) { - _fs = &fs; - - BaseChatMesh::begin(); - - #if defined(NRF52_PLATFORM) || defined(STM32_PLATFORM) - _identity_store = new IdentityStore(fs, ""); - #elif defined(RP2040_PLATFORM) - _identity_store = new IdentityStore(fs, "/identity"); - _identity_store->begin(); - #else - _identity_store = new IdentityStore(fs, "/identity"); - #endif - - loadMainIdentity(); - - // use hex of first 4 bytes of identity public key as default node name - char pub_key_hex[10]; - mesh::Utils::toHex(pub_key_hex, self_id.pub_key, 4); - strcpy(_prefs.node_name, pub_key_hex); - - // if name is provided as a build flag, use that as default node name instead - #ifdef ADVERT_NAME - strcpy(_prefs.node_name, ADVERT_NAME); - #endif - - // load persisted prefs - if (_fs->exists("/new_prefs")) { - loadPrefsInt("/new_prefs"); // new filename - } else if (_fs->exists("/node_prefs")) { - loadPrefsInt("/node_prefs"); - savePrefs(); // save to new filename - _fs->remove("/node_prefs"); // remove old - } - - #ifdef BLE_PIN_CODE - if (_prefs.ble_pin == 0) { - #ifdef DISPLAY_CLASS - if (has_display) { - StdRNG rng; - _active_ble_pin = rng.nextInt(100000, 999999); // random pin each session - } else { - _active_ble_pin = BLE_PIN_CODE; // otherwise static pin - } - #else - _active_ble_pin = BLE_PIN_CODE; // otherwise static pin - #endif - } else { - _active_ble_pin = _prefs.ble_pin; - } - #else - _active_ble_pin = 0; - #endif - - // init 'blob store' support - _fs->mkdir("/bl"); - - loadContacts(); - addChannel("Public", PUBLIC_GROUP_PSK); // pre-configure Andy's public channel - loadChannels(); - - radio_set_params(_prefs.freq, _prefs.bw, _prefs.sf, _prefs.cr); - radio_set_tx_power(_prefs.tx_power_dbm); - } - - const char* getNodeName() { return _prefs.node_name; } - NodePrefs* getNodePrefs() { - return &_prefs; - } - uint32_t getBLEPin() { return _active_ble_pin; } - - void startInterface(BaseSerialInterface& serial) { - _serial = &serial; - serial.enable(); - } - - void savePrefs() { #if defined(NRF52_PLATFORM) || defined(STM32_PLATFORM) - _fs->remove("/new_prefs"); - File file = _fs->open("/new_prefs", FILE_O_WRITE); + #include #elif defined(RP2040_PLATFORM) - File file = _fs->open("/new_prefs", "w"); -#else - File file = _fs->open("/new_prefs", "w", true); + #include +#elif defined(ESP32) + #include #endif - if (file) { - uint8_t pad[8]; - memset(pad, 0, sizeof(pad)); - - file.write((uint8_t *) &_prefs.airtime_factor, sizeof(float)); // 0 - file.write((uint8_t *) _prefs.node_name, sizeof(_prefs.node_name)); // 4 - file.write(pad, 4); // 36 - file.write((uint8_t *) &sensors.node_lat, sizeof(sensors.node_lat)); // 40 - file.write((uint8_t *) &sensors.node_lon, sizeof(sensors.node_lon)); // 48 - file.write((uint8_t *) &_prefs.freq, sizeof(_prefs.freq)); // 56 - file.write((uint8_t *) &_prefs.sf, sizeof(_prefs.sf)); // 60 - file.write((uint8_t *) &_prefs.cr, sizeof(_prefs.cr)); // 61 - file.write((uint8_t *) &_prefs.reserved1, sizeof(_prefs.reserved1)); // 62 - file.write((uint8_t *) &_prefs.manual_add_contacts, sizeof(_prefs.manual_add_contacts)); // 63 - file.write((uint8_t *) &_prefs.bw, sizeof(_prefs.bw)); // 64 - file.write((uint8_t *) &_prefs.tx_power_dbm, sizeof(_prefs.tx_power_dbm)); // 68 - file.write((uint8_t *) &_prefs.telemetry_mode_base, sizeof(_prefs.telemetry_mode_base)); // 69 - file.write((uint8_t *) &_prefs.telemetry_mode_loc, sizeof(_prefs.telemetry_mode_loc)); // 70 - file.write((uint8_t *) &_prefs.telemetry_mode_env, sizeof(_prefs.telemetry_mode_env)); // 71 - file.write((uint8_t *) &_prefs.rx_delay_base, sizeof(_prefs.rx_delay_base)); // 72 - file.write(pad, 4); // 76 - file.write((uint8_t *) &_prefs.ble_pin, sizeof(_prefs.ble_pin)); // 80 - - file.close(); - } - } - - void handleCmdFrame(size_t len) { - if (cmd_frame[0] == CMD_DEVICE_QEURY && len >= 2) { // sent when app establishes connection - app_target_ver = cmd_frame[1]; // which version of protocol does app understand - - int i = 0; - out_frame[i++] = RESP_CODE_DEVICE_INFO; - out_frame[i++] = FIRMWARE_VER_CODE; - out_frame[i++] = MAX_CONTACTS / 2; // v3+ - out_frame[i++] = MAX_GROUP_CHANNELS; // v3+ - memcpy(&out_frame[i], &_prefs.ble_pin, 4); i += 4; - memset(&out_frame[i], 0, 12); - strcpy((char *) &out_frame[i], FIRMWARE_BUILD_DATE); i += 12; - StrHelper::strzcpy((char *) &out_frame[i], board.getManufacturerName(), 40); i += 40; - StrHelper::strzcpy((char *) &out_frame[i], FIRMWARE_VERSION, 20); i += 20; - _serial->writeFrame(out_frame, i); - } else if (cmd_frame[0] == CMD_APP_START && len >= 8) { // sent when app establishes connection, respond with node ID - // cmd_frame[1..7] reserved future - char* app_name = (char *) &cmd_frame[8]; - cmd_frame[len] = 0; // make app_name null terminated - MESH_DEBUG_PRINTLN("App %s connected", app_name); - - _iter_started = false; // stop any left-over ContactsIterator - int i = 0; - out_frame[i++] = RESP_CODE_SELF_INFO; - out_frame[i++] = ADV_TYPE_CHAT; // what this node Advert identifies as (maybe node's pronouns too?? :-) - out_frame[i++] = _prefs.tx_power_dbm; - out_frame[i++] = MAX_LORA_TX_POWER; - memcpy(&out_frame[i], self_id.pub_key, PUB_KEY_SIZE); i += PUB_KEY_SIZE; - - int32_t lat, lon; - lat = (sensors.node_lat * 1000000.0); - lon = (sensors.node_lon * 1000000.0); - memcpy(&out_frame[i], &lat, 4); i += 4; - memcpy(&out_frame[i], &lon, 4); i += 4; - out_frame[i++] = 0; // reserved - out_frame[i++] = 0; // reserved - out_frame[i++] = (_prefs.telemetry_mode_env << 4) | (_prefs.telemetry_mode_loc << 2) | (_prefs.telemetry_mode_base); // v5+ - out_frame[i++] = _prefs.manual_add_contacts; - - uint32_t freq = _prefs.freq * 1000; - memcpy(&out_frame[i], &freq, 4); i += 4; - uint32_t bw = _prefs.bw*1000; - memcpy(&out_frame[i], &bw, 4); i += 4; - out_frame[i++] = _prefs.sf; - out_frame[i++] = _prefs.cr; - - int tlen = strlen(_prefs.node_name); // revisit: UTF_8 ?? - memcpy(&out_frame[i], _prefs.node_name, tlen); i += tlen; - _serial->writeFrame(out_frame, i); - } else if (cmd_frame[0] == CMD_SEND_TXT_MSG && len >= 14) { - int i = 1; - uint8_t txt_type = cmd_frame[i++]; - uint8_t attempt = cmd_frame[i++]; - uint32_t msg_timestamp; - memcpy(&msg_timestamp, &cmd_frame[i], 4); i += 4; - uint8_t* pub_key_prefix = &cmd_frame[i]; i += 6; - ContactInfo* recipient = lookupContactByPubKey(pub_key_prefix, 6); - if (recipient && (txt_type == TXT_TYPE_PLAIN || txt_type == TXT_TYPE_CLI_DATA)) { - char *text = (char *) &cmd_frame[i]; - int tlen = len - i; - uint32_t est_timeout; - text[tlen] = 0; // ensure null - int result; - uint32_t expected_ack; - if (txt_type == TXT_TYPE_CLI_DATA) { - result = sendCommandData(*recipient, msg_timestamp, attempt, text, est_timeout); - expected_ack = 0; // no Ack expected - } else { - result = sendMessage(*recipient, msg_timestamp, attempt, text, expected_ack, est_timeout); - } - // TODO: add expected ACK to table - if (result == MSG_SEND_FAILED) { - writeErrFrame(ERR_CODE_TABLE_FULL); - } else { - if (expected_ack) { - expected_ack_table[next_ack_idx].msg_sent = _ms->getMillis(); // add to circular table - expected_ack_table[next_ack_idx].ack = expected_ack; - next_ack_idx = (next_ack_idx + 1) % EXPECTED_ACK_TABLE_SIZE; - } - - out_frame[0] = RESP_CODE_SENT; - out_frame[1] = (result == MSG_SEND_SENT_FLOOD) ? 1 : 0; - memcpy(&out_frame[2], &expected_ack, 4); - memcpy(&out_frame[6], &est_timeout, 4); - _serial->writeFrame(out_frame, 10); - } - } else { - writeErrFrame(recipient == NULL ? ERR_CODE_NOT_FOUND : ERR_CODE_UNSUPPORTED_CMD); // unknown recipient, or unsuported TXT_TYPE_* - } - } else if (cmd_frame[0] == CMD_SEND_CHANNEL_TXT_MSG) { // send GroupChannel msg - int i = 1; - uint8_t txt_type = cmd_frame[i++]; // should be TXT_TYPE_PLAIN - uint8_t channel_idx = cmd_frame[i++]; - uint32_t msg_timestamp; - memcpy(&msg_timestamp, &cmd_frame[i], 4); i += 4; - const char *text = (char *) &cmd_frame[i]; - - if (txt_type != TXT_TYPE_PLAIN) { - writeErrFrame(ERR_CODE_UNSUPPORTED_CMD); - } else { - ChannelDetails channel; - bool success = getChannel(channel_idx, channel); - if (success && sendGroupMessage(msg_timestamp, channel.channel, _prefs.node_name, text, len - i)) { - writeOKFrame(); - } else { - writeErrFrame(ERR_CODE_NOT_FOUND); // bad channel_idx - } - } - } else if (cmd_frame[0] == CMD_GET_CONTACTS) { // get Contact list - if (_iter_started) { - writeErrFrame(ERR_CODE_BAD_STATE); // iterator is currently busy - } else { - if (len >= 5) { // has optional 'since' param - memcpy(&_iter_filter_since, &cmd_frame[1], 4); - } else { - _iter_filter_since = 0; - } - - uint8_t reply[5]; - reply[0] = RESP_CODE_CONTACTS_START; - uint32_t count = getNumContacts(); // total, NOT filtered count - memcpy(&reply[1], &count, 4); - _serial->writeFrame(reply, 5); - - // start iterator - _iter = startContactsIterator(); - _iter_started = true; - _most_recent_lastmod = 0; - } - } else if (cmd_frame[0] == CMD_SET_ADVERT_NAME && len >= 2) { - int nlen = len - 1; - if (nlen > sizeof(_prefs.node_name)-1) nlen = sizeof(_prefs.node_name)-1; // max len - memcpy(_prefs.node_name, &cmd_frame[1], nlen); - _prefs.node_name[nlen] = 0; // null terminator - savePrefs(); - writeOKFrame(); - } else if (cmd_frame[0] == CMD_SET_ADVERT_LATLON && len >= 9) { - int32_t lat, lon, alt = 0; - memcpy(&lat, &cmd_frame[1], 4); - memcpy(&lon, &cmd_frame[5], 4); - if (len >= 13) { - memcpy(&alt, &cmd_frame[9], 4); // for FUTURE support - } - if (lat <= 90*1E6 && lat >= -90*1E6 && lon <= 180*1E6 && lon >= -180*1E6) { - sensors.node_lat = ((double)lat) / 1000000.0; - sensors.node_lon = ((double)lon) / 1000000.0; - savePrefs(); - writeOKFrame(); - } else { - writeErrFrame(ERR_CODE_ILLEGAL_ARG); // invalid geo coordinate - } - } else if (cmd_frame[0] == CMD_GET_DEVICE_TIME) { - uint8_t reply[5]; - reply[0] = RESP_CODE_CURR_TIME; - uint32_t now = getRTCClock()->getCurrentTime(); - memcpy(&reply[1], &now, 4); - _serial->writeFrame(reply, 5); - } else if (cmd_frame[0] == CMD_SET_DEVICE_TIME && len >= 5) { - uint32_t secs; - memcpy(&secs, &cmd_frame[1], 4); - uint32_t curr = getRTCClock()->getCurrentTime(); - if (secs >= curr) { - getRTCClock()->setCurrentTime(secs); - writeOKFrame(); - } else { - writeErrFrame(ERR_CODE_ILLEGAL_ARG); - } - } else if (cmd_frame[0] == CMD_SEND_SELF_ADVERT) { - auto pkt = createSelfAdvert(_prefs.node_name, sensors.node_lat, sensors.node_lon); - if (pkt) { - if (len >= 2 && cmd_frame[1] == 1) { // optional param (1 = flood, 0 = zero hop) - sendFlood(pkt); - } else { - sendZeroHop(pkt); - } - writeOKFrame(); - } else { - writeErrFrame(ERR_CODE_TABLE_FULL); - } - } else if (cmd_frame[0] == CMD_RESET_PATH && len >= 1+32) { - uint8_t* pub_key = &cmd_frame[1]; - ContactInfo* recipient = lookupContactByPubKey(pub_key, PUB_KEY_SIZE); - if (recipient) { - recipient->out_path_len = -1; - //recipient->lastmod = ?? shouldn't be needed, app already has this version of contact - dirty_contacts_expiry = futureMillis(LAZY_CONTACTS_WRITE_DELAY); - writeOKFrame(); - } else { - writeErrFrame(ERR_CODE_NOT_FOUND); // unknown contact - } - } else if (cmd_frame[0] == CMD_ADD_UPDATE_CONTACT && len >= 1+32+2+1) { - uint8_t* pub_key = &cmd_frame[1]; - ContactInfo* recipient = lookupContactByPubKey(pub_key, PUB_KEY_SIZE); - if (recipient) { - updateContactFromFrame(*recipient, cmd_frame, len); - //recipient->lastmod = ?? shouldn't be needed, app already has this version of contact - dirty_contacts_expiry = futureMillis(LAZY_CONTACTS_WRITE_DELAY); - writeOKFrame(); - } else { - ContactInfo contact; - updateContactFromFrame(contact, cmd_frame, len); - contact.lastmod = getRTCClock()->getCurrentTime(); - contact.sync_since = 0; - if (addContact(contact)) { - dirty_contacts_expiry = futureMillis(LAZY_CONTACTS_WRITE_DELAY); - writeOKFrame(); - } else { - writeErrFrame(ERR_CODE_TABLE_FULL); - } - } - } else if (cmd_frame[0] == CMD_REMOVE_CONTACT) { - uint8_t* pub_key = &cmd_frame[1]; - ContactInfo* recipient = lookupContactByPubKey(pub_key, PUB_KEY_SIZE); - if (recipient && removeContact(*recipient)) { - dirty_contacts_expiry = futureMillis(LAZY_CONTACTS_WRITE_DELAY); - writeOKFrame(); - } else { - writeErrFrame(ERR_CODE_NOT_FOUND); // not found, or unable to remove - } - } else if (cmd_frame[0] == CMD_SHARE_CONTACT) { - uint8_t* pub_key = &cmd_frame[1]; - ContactInfo* recipient = lookupContactByPubKey(pub_key, PUB_KEY_SIZE); - if (recipient) { - if (shareContactZeroHop(*recipient)) { - writeOKFrame(); - } else { - writeErrFrame(ERR_CODE_TABLE_FULL); // unable to send - } - } else { - writeErrFrame(ERR_CODE_NOT_FOUND); - } - } else if (cmd_frame[0] == CMD_GET_CONTACT_BY_KEY) { - uint8_t* pub_key = &cmd_frame[1]; - ContactInfo* contact = lookupContactByPubKey(pub_key, PUB_KEY_SIZE); - if (contact) { - writeContactRespFrame(RESP_CODE_CONTACT, *contact); - } else { - writeErrFrame(ERR_CODE_NOT_FOUND); // not found - } - } else if (cmd_frame[0] == CMD_EXPORT_CONTACT) { - if (len < 1 + PUB_KEY_SIZE) { - // export SELF - auto pkt = createSelfAdvert(_prefs.node_name, sensors.node_lat, sensors.node_lon); - if (pkt) { - pkt->header |= ROUTE_TYPE_FLOOD; // would normally be sent in this mode - - out_frame[0] = RESP_CODE_EXPORT_CONTACT; - uint8_t out_len = pkt->writeTo(&out_frame[1]); - releasePacket(pkt); // undo the obtainNewPacket() - _serial->writeFrame(out_frame, out_len + 1); - } else { - writeErrFrame(ERR_CODE_TABLE_FULL); // Error - } - } else { - uint8_t* pub_key = &cmd_frame[1]; - ContactInfo* recipient = lookupContactByPubKey(pub_key, PUB_KEY_SIZE); - uint8_t out_len; - if (recipient && (out_len = exportContact(*recipient, &out_frame[1])) > 0) { - out_frame[0] = RESP_CODE_EXPORT_CONTACT; - _serial->writeFrame(out_frame, out_len + 1); - } else { - writeErrFrame(ERR_CODE_NOT_FOUND); // not found - } - } - } else if (cmd_frame[0] == CMD_IMPORT_CONTACT && len > 2+32+64) { - if (importContact(&cmd_frame[1], len - 1)) { - writeOKFrame(); - } else { - writeErrFrame(ERR_CODE_ILLEGAL_ARG); - } - } else if (cmd_frame[0] == CMD_SYNC_NEXT_MESSAGE) { - int out_len; - if ((out_len = getFromOfflineQueue(out_frame)) > 0) { - _serial->writeFrame(out_frame, out_len); - #ifdef DISPLAY_CLASS - ui_task.msgRead(offline_queue_len); - #endif - } else { - out_frame[0] = RESP_CODE_NO_MORE_MESSAGES; - _serial->writeFrame(out_frame, 1); - } - } else if (cmd_frame[0] == CMD_SET_RADIO_PARAMS) { - int i = 1; - uint32_t freq; - memcpy(&freq, &cmd_frame[i], 4); i += 4; - uint32_t bw; - memcpy(&bw, &cmd_frame[i], 4); i += 4; - uint8_t sf = cmd_frame[i++]; - uint8_t cr = cmd_frame[i++]; - - if (freq >= 300000 && freq <= 2500000 && sf >= 7 && sf <= 12 && cr >= 5 && cr <= 8 && bw >= 7000 && bw <= 500000) { - _prefs.sf = sf; - _prefs.cr = cr; - _prefs.freq = (float)freq / 1000.0; - _prefs.bw = (float)bw / 1000.0; - savePrefs(); - - radio_set_params(_prefs.freq, _prefs.bw, _prefs.sf, _prefs.cr); - MESH_DEBUG_PRINTLN("OK: CMD_SET_RADIO_PARAMS: f=%d, bw=%d, sf=%d, cr=%d", freq, bw, (uint32_t)sf, (uint32_t)cr); - - writeOKFrame(); - } else { - MESH_DEBUG_PRINTLN("Error: CMD_SET_RADIO_PARAMS: f=%d, bw=%d, sf=%d, cr=%d", freq, bw, (uint32_t)sf, (uint32_t)cr); - writeErrFrame(ERR_CODE_ILLEGAL_ARG); - } - } else if (cmd_frame[0] == CMD_SET_RADIO_TX_POWER) { - if (cmd_frame[1] > MAX_LORA_TX_POWER) { - writeErrFrame(ERR_CODE_ILLEGAL_ARG); - } else { - _prefs.tx_power_dbm = cmd_frame[1]; - savePrefs(); - radio_set_tx_power(_prefs.tx_power_dbm); - writeOKFrame(); - } - } else if (cmd_frame[0] == CMD_SET_TUNING_PARAMS) { - int i = 1; - uint32_t rx, af; - memcpy(&rx, &cmd_frame[i], 4); i += 4; - memcpy(&af, &cmd_frame[i], 4); i += 4; - _prefs.rx_delay_base = ((float)rx) / 1000.0f; - _prefs.airtime_factor = ((float)af) / 1000.0f; - savePrefs(); - writeOKFrame(); - } else if (cmd_frame[0] == CMD_SET_OTHER_PARAMS) { - _prefs.manual_add_contacts = cmd_frame[1]; - if (len >= 3) { - _prefs.telemetry_mode_base = cmd_frame[2] & 0x03; // v5+ - _prefs.telemetry_mode_loc = (cmd_frame[2] >> 2) & 0x03; - _prefs.telemetry_mode_env = (cmd_frame[2] >> 4) & 0x03; - } - savePrefs(); - writeOKFrame(); - } else if (cmd_frame[0] == CMD_REBOOT && memcmp(&cmd_frame[1], "reboot", 6) == 0) { - if (dirty_contacts_expiry) { // is there are pending dirty contacts write needed? - saveContacts(); - } - board.reboot(); - } else if (cmd_frame[0] == CMD_GET_BATTERY_VOLTAGE) { - uint8_t reply[3]; - reply[0] = RESP_CODE_BATTERY_VOLTAGE; - uint16_t battery_millivolts = board.getBattMilliVolts(); - memcpy(&reply[1], &battery_millivolts, 2); - _serial->writeFrame(reply, 3); - } else if (cmd_frame[0] == CMD_EXPORT_PRIVATE_KEY) { - #if ENABLE_PRIVATE_KEY_EXPORT - uint8_t reply[65]; - reply[0] = RESP_CODE_PRIVATE_KEY; - self_id.writeTo(&reply[1], 64); - _serial->writeFrame(reply, 65); - #else - writeDisabledFrame(); - #endif - } else if (cmd_frame[0] == CMD_IMPORT_PRIVATE_KEY && len >= 65) { - #if ENABLE_PRIVATE_KEY_IMPORT - mesh::LocalIdentity identity; - identity.readFrom(&cmd_frame[1], 64); - if (saveMainIdentity(identity)) { - self_id = identity; - writeOKFrame(); - } else { - writeErrFrame(ERR_CODE_FILE_IO_ERROR); - } - #else - writeDisabledFrame(); - #endif - } else if (cmd_frame[0] == CMD_SEND_RAW_DATA && len >= 6) { - int i = 1; - int8_t path_len = cmd_frame[i++]; - if (path_len >= 0 && i + path_len + 4 <= len) { // minimum 4 byte payload - uint8_t* path = &cmd_frame[i]; i += path_len; - auto pkt = createRawData(&cmd_frame[i], len - i); - if (pkt) { - sendDirect(pkt, path, path_len); - writeOKFrame(); - } else { - writeErrFrame(ERR_CODE_TABLE_FULL); - } - } else { - writeErrFrame(ERR_CODE_UNSUPPORTED_CMD); // flood, not supported (yet) - } - } else if (cmd_frame[0] == CMD_SEND_LOGIN && len >= 1+PUB_KEY_SIZE) { - uint8_t* pub_key = &cmd_frame[1]; - ContactInfo* recipient = lookupContactByPubKey(pub_key, PUB_KEY_SIZE); - char *password = (char *) &cmd_frame[1+PUB_KEY_SIZE]; - cmd_frame[len] = 0; // ensure null terminator in password - if (recipient) { - uint32_t est_timeout; - int result = sendLogin(*recipient, password, est_timeout); - if (result == MSG_SEND_FAILED) { - writeErrFrame(ERR_CODE_TABLE_FULL); - } else { - pending_telemetry = pending_status = 0; - memcpy(&pending_login, recipient->id.pub_key, 4); // match this to onContactResponse() - out_frame[0] = RESP_CODE_SENT; - out_frame[1] = (result == MSG_SEND_SENT_FLOOD) ? 1 : 0; - memcpy(&out_frame[2], &pending_login, 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) { - uint8_t* pub_key = &cmd_frame[1]; - ContactInfo* recipient = lookupContactByPubKey(pub_key, PUB_KEY_SIZE); - if (recipient) { - uint32_t tag, est_timeout; - int result = sendRequest(*recipient, REQ_TYPE_GET_STATUS, tag, est_timeout); - if (result == MSG_SEND_FAILED) { - writeErrFrame(ERR_CODE_TABLE_FULL); - } else { - pending_telemetry = pending_login = 0; - // FUTURE: pending_status = tag; // match this in onContactResponse() - memcpy(&pending_status, recipient->id.pub_key, 4); // legacy matching scheme - 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_TELEMETRY_REQ && len >= 4+PUB_KEY_SIZE) { - uint8_t* pub_key = &cmd_frame[4]; - ContactInfo* recipient = lookupContactByPubKey(pub_key, PUB_KEY_SIZE); - if (recipient) { - uint32_t tag, est_timeout; - int result = sendRequest(*recipient, REQ_TYPE_GET_TELEMETRY_DATA, tag, est_timeout); - if (result == MSG_SEND_FAILED) { - writeErrFrame(ERR_CODE_TABLE_FULL); - } else { - pending_status = pending_login = 0; - pending_telemetry = tag; // match this in 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_HAS_CONNECTION && len >= 1+PUB_KEY_SIZE) { - uint8_t* pub_key = &cmd_frame[1]; - if (hasConnectionTo(pub_key)) { - writeOKFrame(); - } else { - writeErrFrame(ERR_CODE_NOT_FOUND); - } - } else if (cmd_frame[0] == CMD_LOGOUT && len >= 1+PUB_KEY_SIZE) { - uint8_t* pub_key = &cmd_frame[1]; - stopConnection(pub_key); - writeOKFrame(); - } else if (cmd_frame[0] == CMD_GET_CHANNEL && len >= 2) { - uint8_t channel_idx = cmd_frame[1]; - ChannelDetails channel; - if (getChannel(channel_idx, channel)) { - int i = 0; - out_frame[i++] = RESP_CODE_CHANNEL_INFO; - out_frame[i++] = channel_idx; - strcpy((char *)&out_frame[i], channel.name); i += 32; - memcpy(&out_frame[i], channel.channel.secret, 16); i += 16; // NOTE: only 128-bit supported - _serial->writeFrame(out_frame, i); - } else { - writeErrFrame(ERR_CODE_NOT_FOUND); - } - } else if (cmd_frame[0] == CMD_SET_CHANNEL && len >= 2+32+32) { - writeErrFrame(ERR_CODE_UNSUPPORTED_CMD); // not supported (yet) - } else if (cmd_frame[0] == CMD_SET_CHANNEL && len >= 2+32+16) { - uint8_t channel_idx = cmd_frame[1]; - ChannelDetails channel; - StrHelper::strncpy(channel.name, (char *) &cmd_frame[2], 32); - memset(channel.channel.secret, 0, sizeof(channel.channel.secret)); - memcpy(channel.channel.secret, &cmd_frame[2+32], 16); // NOTE: only 128-bit supported - if (setChannel(channel_idx, channel)) { - saveChannels(); - writeOKFrame(); - } else { - writeErrFrame(ERR_CODE_NOT_FOUND); // bad channel_idx - } - } else if (cmd_frame[0] == CMD_SIGN_START) { - out_frame[0] = RESP_CODE_SIGN_START; - out_frame[1] = 0; // reserved - uint32_t len = MAX_SIGN_DATA_LEN; - memcpy(&out_frame[2], &len, 4); - _serial->writeFrame(out_frame, 6); - - if (sign_data) { - free(sign_data); - } - sign_data = (uint8_t *) malloc(MAX_SIGN_DATA_LEN); - sign_data_len = 0; - } else if (cmd_frame[0] == CMD_SIGN_DATA && len > 1) { - if (sign_data == NULL || sign_data_len + (len - 1) > MAX_SIGN_DATA_LEN) { - writeErrFrame(sign_data == NULL ? ERR_CODE_BAD_STATE : ERR_CODE_TABLE_FULL); // error: too long - } else { - memcpy(&sign_data[sign_data_len], &cmd_frame[1], len - 1); - sign_data_len += (len - 1); - writeOKFrame(); - } - } else if (cmd_frame[0] == CMD_SIGN_FINISH) { - if (sign_data) { - self_id.sign(&out_frame[1], sign_data, sign_data_len); - - free(sign_data); // don't need sign_data now - sign_data = NULL; - - out_frame[0] = RESP_CODE_SIGNATURE; - _serial->writeFrame(out_frame, 1 + SIGNATURE_SIZE); - } else { - writeErrFrame(ERR_CODE_BAD_STATE); - } - } else if (cmd_frame[0] == CMD_SEND_TRACE_PATH && len > 10 && len - 10 < MAX_PATH_SIZE) { - uint32_t tag, auth; - memcpy(&tag, &cmd_frame[1], 4); - memcpy(&auth, &cmd_frame[5], 4); - auto pkt = createTrace(tag, auth, cmd_frame[9]); - if (pkt) { - uint8_t path_len = len - 10; - sendDirect(pkt, &cmd_frame[10], path_len); - - uint32_t t = _radio->getEstAirtimeFor(pkt->payload_len + pkt->path_len + 2); - uint32_t est_timeout = calcDirectTimeoutMillisFor(t, path_len); - - out_frame[0] = RESP_CODE_SENT; - out_frame[1] = 0; - memcpy(&out_frame[2], &tag, 4); - memcpy(&out_frame[6], &est_timeout, 4); - _serial->writeFrame(out_frame, 10); - } else { - writeErrFrame(ERR_CODE_TABLE_FULL); - } - } else if (cmd_frame[0] == CMD_SET_DEVICE_PIN && len >= 5) { - - // get pin from command frame - uint32_t pin; - memcpy(&pin, &cmd_frame[1], 4); - - // ensure pin is zero, or a valid 6 digit pin - if(pin == 0 || (pin >= 100000 && pin <= 999999)){ - _prefs.ble_pin = pin; - savePrefs(); - writeOKFrame(); - } else { - writeErrFrame(ERR_CODE_ILLEGAL_ARG); - } - - } else if (cmd_frame[0] == CMD_GET_CUSTOM_VARS) { - out_frame[0] = RESP_CODE_CUSTOM_VARS; - char* dp = (char *) &out_frame[1]; - for (int i = 0; i < sensors.getNumSettings() && dp - (char *) &out_frame[1] < 140; i++) { - if (i > 0) { *dp++ = ','; } - strcpy(dp, sensors.getSettingName(i)); dp = strchr(dp, 0); - *dp++ = ':'; - strcpy(dp, sensors.getSettingValue(i)); dp = strchr(dp, 0); - } - _serial->writeFrame(out_frame, dp - (char *)out_frame); - } else if (cmd_frame[0] == CMD_SET_CUSTOM_VAR && len >= 4) { - cmd_frame[len] = 0; - char* sp = (char *) &cmd_frame[1]; - char* np = strchr(sp, ':'); // look for separator char - if (np) { - *np++ = 0; // modify 'cmd_frame', replace ':' with null - bool success = sensors.setSettingValue(sp, np); - if (success) { - writeOKFrame(); - } else { - writeErrFrame(ERR_CODE_ILLEGAL_ARG); - } - } else { - writeErrFrame(ERR_CODE_ILLEGAL_ARG); - } - } else { - writeErrFrame(ERR_CODE_UNSUPPORTED_CMD); - MESH_DEBUG_PRINTLN("ERROR: unknown command: %02X", cmd_frame[0]); - } - } - - void loop() { - BaseChatMesh::loop(); - - size_t len = _serial->checkRecvFrame(cmd_frame); - if (len > 0) { - handleCmdFrame(len); - } else if (_iter_started // check if our ContactsIterator is 'running' - && !_serial->isWriteBusy() // don't spam the Serial Interface too quickly! - ) { - ContactInfo contact; - if (_iter.hasNext(this, contact)) { - if (contact.lastmod > _iter_filter_since) { // apply the 'since' filter - writeContactRespFrame(RESP_CODE_CONTACT, contact); - if (contact.lastmod > _most_recent_lastmod) { - _most_recent_lastmod = contact.lastmod; // save for the RESP_CODE_END_OF_CONTACTS frame - } - } - } else { // EOF - out_frame[0] = RESP_CODE_END_OF_CONTACTS; - memcpy(&out_frame[1], &_most_recent_lastmod, 4); // include the most recent lastmod, so app can update their 'since' - _serial->writeFrame(out_frame, 5); - _iter_started = false; - } - } else if (!_serial->isWriteBusy()) { - checkConnections(); - } - - // is there are pending dirty contacts write needed? - if (dirty_contacts_expiry && millisHasNowPassed(dirty_contacts_expiry)) { - saveContacts(); - dirty_contacts_expiry = 0; - } - - #ifdef DISPLAY_CLASS - ui_task.setHasConnection(_serial->isConnected()); - ui_task.loop(); - #endif - } -}; #ifdef ESP32 #ifdef WIFI_SSID @@ -1641,10 +71,18 @@ class MyMesh : public BaseChatMesh { #error "need to define a serial interface" #endif +/* GLOBAL OBJECTS */ StdRNG fast_rng; SimpleMeshTables tables; MyMesh the_mesh(radio_driver, fast_rng, *new VolatileRTCClock(), tables); // TODO: test with 'rtc_clock' in target.cpp +#ifdef DISPLAY_CLASS + #include "UITask.h" + UITask ui_task(&board); +#endif +/* END GLOBAL OBJECTS */ + + void halt() { while (1) ; } diff --git a/variants/generic_espnow/platformio.ini b/variants/generic_espnow/platformio.ini index 8a033a62a..b3ae7e450 100644 --- a/variants/generic_espnow/platformio.ini +++ b/variants/generic_espnow/platformio.ini @@ -62,7 +62,7 @@ build_flags = ; NOTE: DO NOT ENABLE --> -D MESH_DEBUG=1 ; NOTE: DO NOT ENABLE --> -D ESPNOW_DEBUG_LOGGING=1 build_src_filter = ${Generic_ESPNOW.build_src_filter} - +<../examples/companion_radio/main.cpp> + +<../examples/companion_radio> lib_deps = ${Generic_ESPNOW.lib_deps} densaugeo/base64 @ ~1.4.0 diff --git a/variants/promicro/platformio.ini b/variants/promicro/platformio.ini index 11f73d811..497716248 100644 --- a/variants/promicro/platformio.ini +++ b/variants/promicro/platformio.ini @@ -186,7 +186,7 @@ build_flags = ${ProMicroLLCC68.build_flags} ; NOTE: DO NOT ENABLE --> -D MESH_PACKET_LOGGING=1 ; NOTE: DO NOT ENABLE --> -D MESH_DEBUG=1 build_src_filter = ${ProMicroLLCC68.build_src_filter} - +<../examples/companion_radio/main.cpp> + +<../examples/companion_radio> lib_deps = ${ProMicroLLCC68.lib_deps} adafruit/RTClib @ ^2.1.3 densaugeo/base64 @ ~1.4.0 @@ -205,7 +205,7 @@ build_flags = ${ProMicroLLCC68.build_flags} ; -D MESH_DEBUG=1 build_src_filter = ${ProMicroLLCC68.build_src_filter} + - +<../examples/companion_radio/main.cpp> + +<../examples/companion_radio> lib_deps = ${ProMicroLLCC68.lib_deps} adafruit/RTClib @ ^2.1.3 densaugeo/base64 @ ~1.4.0 diff --git a/variants/t114/platformio.ini b/variants/t114/platformio.ini index 37e31e6fb..c4569cf8b 100644 --- a/variants/t114/platformio.ini +++ b/variants/t114/platformio.ini @@ -75,7 +75,7 @@ build_flags = ; -D ENABLE_PRIVATE_KEY_IMPORT=1 ; -D ENABLE_PRIVATE_KEY_EXPORT=1 ; -D MESH_PACKET_LOGGING=1 -; -D MESH_DEBUG=1 + -D MESH_DEBUG=1 build_src_filter = ${Heltec_t114.build_src_filter} + + @@ -102,7 +102,7 @@ build_flags = ; -D MESH_DEBUG=1 build_src_filter = ${Heltec_t114.build_src_filter} + - +<../examples/companion_radio/main.cpp> + +<../examples/companion_radio> lib_deps = ${Heltec_t114.lib_deps} densaugeo/base64 @ ~1.4.0 \ No newline at end of file diff --git a/variants/xiao_nrf52/platformio.ini b/variants/xiao_nrf52/platformio.ini index 2f468f4f1..45d28740f 100644 --- a/variants/xiao_nrf52/platformio.ini +++ b/variants/xiao_nrf52/platformio.ini @@ -68,7 +68,7 @@ build_flags = ; -D MESH_DEBUG=1 build_src_filter = ${Xiao_nrf52.build_src_filter} + - +<../examples/companion_radio/main.cpp> + +<../examples/companion_radio> lib_deps = ${Xiao_nrf52.lib_deps} densaugeo/base64 @ ~1.4.0 @@ -84,7 +84,7 @@ build_flags = ; -D MESH_DEBUG=1 build_src_filter = ${Xiao_nrf52.build_src_filter} + - +<../examples/companion_radio/main.cpp> + +<../examples/companion_radio> lib_deps = ${Xiao_nrf52.lib_deps} densaugeo/base64 @ ~1.4.0 diff --git a/variants/xiao_s3_wio/platformio.ini b/variants/xiao_s3_wio/platformio.ini index 841a50c3b..cfc8e7740 100644 --- a/variants/xiao_s3_wio/platformio.ini +++ b/variants/xiao_s3_wio/platformio.ini @@ -108,7 +108,7 @@ build_flags = ; -D MESH_DEBUG=1 build_src_filter = ${Xiao_S3_WIO.build_src_filter} + - +<../examples/companion_radio/main.cpp> + +<../examples/companion_radio> lib_deps = ${Xiao_S3_WIO.lib_deps} densaugeo/base64 @ ~1.4.0 From 053aa0b3d690dced2628b58bea5ad48c77846632 Mon Sep 17 00:00:00 2001 From: hank Date: Sun, 1 Jun 2025 09:24:10 -0700 Subject: [PATCH 02/19] Adding clang-format --- .clang-format | 84 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 84 insertions(+) create mode 100644 .clang-format diff --git a/.clang-format b/.clang-format new file mode 100644 index 000000000..80c7a10af --- /dev/null +++ b/.clang-format @@ -0,0 +1,84 @@ +# .clang-format +Language: Cpp +AccessModifierOffset: -2 +AlignAfterOpenBracket: Align +AlignConsecutiveAssignments: false +AlignConsecutiveDeclarations: false +AlignConsecutiveMacros: + Enabled: true + AcrossEmptyLines: true + AcrossComments: true +AlignOperands: true +AlignTrailingComments: true +AllowAllParametersOfDeclarationOnNextLine: false +AllowShortBlocksOnASingleLine: false +AllowShortCaseLabelsOnASingleLine: false +AllowShortFunctionsOnASingleLine: Inline +AllowShortIfStatementsOnASingleLine: false +AllowShortLoopsOnASingleLine: false +AlwaysBreakAfterDefinitionReturnType: None +AlwaysBreakAfterReturnType: None +AlwaysBreakBeforeMultilineStrings: false +AlwaysBreakTemplateDeclarations: No +BinPackArguments: true +BinPackParameters: true +BraceWrapping: + AfterClass: false + AfterControlStatement: false + AfterEnum: false + AfterFunction: false + AfterNamespace: false + AfterObjCDeclaration: false + AfterStruct: false + AfterUnion: false + BeforeCatch: true + BeforeElse: true + IndentBraces: false +BreakBeforeBinaryOperators: None +BreakBeforeBraces: Stroustrup +BreakBeforeTernaryOperators: true +BreakConstructorInitializersBeforeComma: false +ColumnLimit: 110 +CommentPragmas: '^ IWYU pragma:' +CompactNamespaces: false +ConstructorInitializerAllOnOneLineOrOnePerLine: false +Cpp11BracedListStyle: false +DerivePointerAlignment: false +DisableFormat: false +IncludeBlocks: Regroup +IndentCaseLabels: false +IndentPPDirectives: None +IndentWidth: 2 +IndentWrappedFunctionNames: false +KeepEmptyLinesAtTheStartOfBlocks: true +MacroBlockBegin: '' +MacroBlockEnd: '' +MaxEmptyLinesToKeep: 1 +NamespaceIndentation: None +ObjCBinPackProtocolList: Auto +PenaltyBreakBeforeFirstCallParameter: 19 +PenaltyBreakComment: 300 +PenaltyBreakFirstLessLess: 120 +PenaltyBreakString: 1000 +PenaltyExcessCharacter: 100000 +PenaltyReturnTypeOnItsOwnLine: 60 +PointerAlignment: Right +ReflowComments: true +SortIncludes: true +SpaceAfterCStyleCast: false +SpaceAfterTemplateKeyword: true +SpaceBeforeAssignmentOperators: true +SpaceBeforeCtorInitializerColon: true +SpaceBeforeInheritanceColon: true +SpaceBeforeParens: ControlStatements +SpaceInEmptyParentheses: false +SpacesBeforeTrailingComments: 1 +SpacesInAngles: false +SpacesInContainerLiterals: false +SpacesInCStyleCastParentheses: false +SpacesInParentheses: false +SpacesInSquareBrackets: false +Standard: Auto +TabWidth: 2 +UseTab: Never +AlignEscapedNewlines: LeftWithLastLine \ No newline at end of file From 5bf58127553b0fe0ba4d9f8355124f2764c60293 Mon Sep 17 00:00:00 2001 From: hank Date: Sun, 1 Jun 2025 09:24:32 -0700 Subject: [PATCH 03/19] Removing debug mode --- variants/t114/platformio.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/variants/t114/platformio.ini b/variants/t114/platformio.ini index c4569cf8b..fd9d6f345 100644 --- a/variants/t114/platformio.ini +++ b/variants/t114/platformio.ini @@ -75,7 +75,7 @@ build_flags = ; -D ENABLE_PRIVATE_KEY_IMPORT=1 ; -D ENABLE_PRIVATE_KEY_EXPORT=1 ; -D MESH_PACKET_LOGGING=1 - -D MESH_DEBUG=1 +; -D MESH_DEBUG=1 build_src_filter = ${Heltec_t114.build_src_filter} + + From f7f96ad372727e7a981480398ca43952bf9e5065 Mon Sep 17 00:00:00 2001 From: hank Date: Sun, 1 Jun 2025 09:25:17 -0700 Subject: [PATCH 04/19] Reformatting code --- examples/companion_radio/Button.cpp | 225 ++++---- examples/companion_radio/Button.h | 112 ++-- examples/companion_radio/MyMesh.cpp | 788 +++++++++++---------------- examples/companion_radio/MyMesh.h | 358 +++++------- examples/companion_radio/NodePrefs.h | 16 +- examples/companion_radio/UITask.h | 47 +- examples/simple_secure_chat/main.cpp | 424 ++++++++------ 7 files changed, 925 insertions(+), 1045 deletions(-) diff --git a/examples/companion_radio/Button.cpp b/examples/companion_radio/Button.cpp index ec1f0f69b..5de4b7024 100644 --- a/examples/companion_radio/Button.cpp +++ b/examples/companion_radio/Button.cpp @@ -1,125 +1,142 @@ #include "Button.h" -Button::Button(uint8_t pin, bool activeState) - : _pin(pin), _activeState(activeState), _isAnalog(false), _analogThreshold(20) { - _currentState = false; // Initialize as not pressed - _lastState = _currentState; +Button::Button(uint8_t pin, bool activeState) + : _pin(pin), _activeState(activeState), _isAnalog(false), _analogThreshold(20) +{ + _currentState = false; // Initialize as not pressed + _lastState = _currentState; } Button::Button(uint8_t pin, bool activeState, bool isAnalog, uint16_t analogThreshold) - : _pin(pin), _activeState(activeState), _isAnalog(isAnalog), _analogThreshold(analogThreshold) { - _currentState = false; // Initialize as not pressed - _lastState = _currentState; + : _pin(pin), _activeState(activeState), _isAnalog(isAnalog), _analogThreshold(analogThreshold) +{ + _currentState = false; // Initialize as not pressed + _lastState = _currentState; } -void Button::begin() { - _currentState = readButton(); - _lastState = _currentState; +void Button::begin() +{ + _currentState = readButton(); + _lastState = _currentState; } -void Button::update() { - uint32_t now = millis(); - - // Read button at specified interval - if (now - _lastReadTime < BUTTON_READ_INTERVAL_MS) { - return; - } - _lastReadTime = now; - - bool newState = readButton(); - - // Check if state has changed - if (newState != _lastState) { - _stateChangeTime = now; +void Button::update() +{ + uint32_t now = millis(); + + // Read button at specified interval + if (now - _lastReadTime < BUTTON_READ_INTERVAL_MS) { + return; + } + _lastReadTime = now; + + bool newState = readButton(); + + // Check if state has changed + if (newState != _lastState) { + _stateChangeTime = now; + } + + // Debounce check + if ((now - _stateChangeTime) > BUTTON_DEBOUNCE_TIME_MS) { + if (newState != _currentState) { + _currentState = newState; + handleStateChange(); } - - // Debounce check - if ((now - _stateChangeTime) > BUTTON_DEBOUNCE_TIME_MS) { - if (newState != _currentState) { - _currentState = newState; - handleStateChange(); - } + } + + _lastState = newState; + + // Handle multi-click timeout + if (_state == WAITING_FOR_MULTI_CLICK && (now - _releaseTime) > BUTTON_CLICK_TIMEOUT_MS) { + // Timeout reached, process the clicks + if (_clickCount == 1) { + triggerEvent(SHORT_PRESS); } - - _lastState = newState; - - // Handle multi-click timeout - if (_state == WAITING_FOR_MULTI_CLICK && (now - _releaseTime) > BUTTON_CLICK_TIMEOUT_MS) { - // Timeout reached, process the clicks - if (_clickCount == 1) { - triggerEvent(SHORT_PRESS); - } else if (_clickCount == 2) { - triggerEvent(DOUBLE_PRESS); - } else if (_clickCount >= 3) { - triggerEvent(TRIPLE_PRESS); - } - _clickCount = 0; - _state = IDLE; + else if (_clickCount == 2) { + triggerEvent(DOUBLE_PRESS); } - - // Handle long press while button is held - if (_state == PRESSED && (now - _pressTime) > BUTTON_LONG_PRESS_TIME_MS) { - triggerEvent(LONG_PRESS); - _state = IDLE; // Prevent multiple press events - _clickCount = 0; + else if (_clickCount >= 3) { + triggerEvent(TRIPLE_PRESS); } + _clickCount = 0; + _state = IDLE; + } + + // Handle long press while button is held + if (_state == PRESSED && (now - _pressTime) > BUTTON_LONG_PRESS_TIME_MS) { + triggerEvent(LONG_PRESS); + _state = IDLE; // Prevent multiple press events + _clickCount = 0; + } } -bool Button::readButton() { - if (_isAnalog) { - return (analogRead(_pin) < _analogThreshold); - } else { - return (digitalRead(_pin) == _activeState); - } +bool Button::readButton() +{ + if (_isAnalog) { + return (analogRead(_pin) < _analogThreshold); + } + else { + return (digitalRead(_pin) == _activeState); + } } -void Button::handleStateChange() { - uint32_t now = millis(); - - if (_currentState) { - // Button pressed - _pressTime = now; - _state = PRESSED; - triggerEvent(ANY_PRESS); - } else { - // Button released - if (_state == PRESSED) { - uint32_t pressDuration = now - _pressTime; - - if (pressDuration < BUTTON_LONG_PRESS_TIME_MS) { - // Short press detected - _clickCount++; - _releaseTime = now; - _state = WAITING_FOR_MULTI_CLICK; - } else { - // Long press already handled in update() - _state = IDLE; - _clickCount = 0; - } - } +void Button::handleStateChange() +{ + uint32_t now = millis(); + + if (_currentState) { + // Button pressed + _pressTime = now; + _state = PRESSED; + triggerEvent(ANY_PRESS); + } + else { + // Button released + if (_state == PRESSED) { + uint32_t pressDuration = now - _pressTime; + + if (pressDuration < BUTTON_LONG_PRESS_TIME_MS) { + // Short press detected + _clickCount++; + _releaseTime = now; + _state = WAITING_FOR_MULTI_CLICK; + } + else { + // Long press already handled in update() + _state = IDLE; + _clickCount = 0; + } } + } } -void Button::triggerEvent(EventType event) { - _lastEvent = event; - - switch (event) { - case ANY_PRESS: - if (_onAnyPress) _onAnyPress(); - break; - case SHORT_PRESS: - if (_onShortPress) _onShortPress(); - break; - case DOUBLE_PRESS: - if (_onDoublePress) _onDoublePress(); - break; - case TRIPLE_PRESS: - if (_onTriplePress) _onTriplePress(); - break; - case LONG_PRESS: - if (_onLongPress) _onLongPress(); - break; - default: - break; - } +void Button::triggerEvent(EventType event) +{ + _lastEvent = event; + + switch (event) { + case ANY_PRESS: + if (_onAnyPress) + _onAnyPress(); + break; + case SHORT_PRESS: + if (_onShortPress) + _onShortPress(); + break; + case DOUBLE_PRESS: + if (_onDoublePress) + _onDoublePress(); + break; + case TRIPLE_PRESS: + if (_onTriplePress) + _onTriplePress(); + break; + case LONG_PRESS: + if (_onLongPress) + _onLongPress(); + break; + default: + break; + } } \ No newline at end of file diff --git a/examples/companion_radio/Button.h b/examples/companion_radio/Button.h index 47c792bd7..855645938 100644 --- a/examples/companion_radio/Button.h +++ b/examples/companion_radio/Button.h @@ -4,74 +4,62 @@ #include // Button timing configuration -#define BUTTON_DEBOUNCE_TIME_MS 50 // Debounce time in ms -#define BUTTON_CLICK_TIMEOUT_MS 500 // Max time between clicks for multi-click -#define BUTTON_LONG_PRESS_TIME_MS 3000 // Time to trigger long press (3 seconds) -#define BUTTON_READ_INTERVAL_MS 10 // How often to read the button +#define BUTTON_DEBOUNCE_TIME_MS 50 // Debounce time in ms +#define BUTTON_CLICK_TIMEOUT_MS 500 // Max time between clicks for multi-click +#define BUTTON_LONG_PRESS_TIME_MS 3000 // Time to trigger long press (3 seconds) +#define BUTTON_READ_INTERVAL_MS 10 // How often to read the button class Button { public: - enum EventType { - NONE, - SHORT_PRESS, - DOUBLE_PRESS, - TRIPLE_PRESS, - LONG_PRESS, - ANY_PRESS - }; + enum EventType { NONE, SHORT_PRESS, DOUBLE_PRESS, TRIPLE_PRESS, LONG_PRESS, ANY_PRESS }; - using EventCallback = std::function; + using EventCallback = std::function; - Button(uint8_t pin, bool activeState = LOW); - Button(uint8_t pin, bool activeState, bool isAnalog, uint16_t analogThreshold = 20); - - void begin(); - void update(); - - // Set callbacks for different events - void onShortPress(EventCallback callback) { _onShortPress = callback; } - void onDoublePress(EventCallback callback) { _onDoublePress = callback; } - void onTriplePress(EventCallback callback) { _onTriplePress = callback; } - void onLongPress(EventCallback callback) { _onLongPress = callback; } - void onAnyPress(EventCallback callback) { _onAnyPress = callback; } - - // State getters - bool isPressed() const { return _currentState; } - EventType getLastEvent() const { return _lastEvent; } + Button(uint8_t pin, bool activeState = LOW); + Button(uint8_t pin, bool activeState, bool isAnalog, uint16_t analogThreshold = 20); + + void begin(); + void update(); + + // Set callbacks for different events + void onShortPress(EventCallback callback) { _onShortPress = callback; } + void onDoublePress(EventCallback callback) { _onDoublePress = callback; } + void onTriplePress(EventCallback callback) { _onTriplePress = callback; } + void onLongPress(EventCallback callback) { _onLongPress = callback; } + void onAnyPress(EventCallback callback) { _onAnyPress = callback; } + + // State getters + bool isPressed() const { return _currentState; } + EventType getLastEvent() const { return _lastEvent; } private: - enum State { - IDLE, - PRESSED, - RELEASED, - WAITING_FOR_MULTI_CLICK - }; + enum State { IDLE, PRESSED, RELEASED, WAITING_FOR_MULTI_CLICK }; + + uint8_t _pin; + bool _activeState; + bool _isAnalog; + uint16_t _analogThreshold; + + State _state = IDLE; + bool _currentState; + bool _lastState; + + uint32_t _stateChangeTime = 0; + uint32_t _pressTime = 0; + uint32_t _releaseTime = 0; + uint32_t _lastReadTime = 0; + + uint8_t _clickCount = 0; + EventType _lastEvent = NONE; + + // Callbacks + EventCallback _onShortPress = nullptr; + EventCallback _onDoublePress = nullptr; + EventCallback _onTriplePress = nullptr; + EventCallback _onLongPress = nullptr; + EventCallback _onAnyPress = nullptr; - uint8_t _pin; - bool _activeState; - bool _isAnalog; - uint16_t _analogThreshold; - - State _state = IDLE; - bool _currentState; - bool _lastState; - - uint32_t _stateChangeTime = 0; - uint32_t _pressTime = 0; - uint32_t _releaseTime = 0; - uint32_t _lastReadTime = 0; - - uint8_t _clickCount = 0; - EventType _lastEvent = NONE; - - // Callbacks - EventCallback _onShortPress = nullptr; - EventCallback _onDoublePress = nullptr; - EventCallback _onTriplePress = nullptr; - EventCallback _onLongPress = nullptr; - EventCallback _onAnyPress = nullptr; - - bool readButton(); - void handleStateChange(); - void triggerEvent(EventType event); + bool readButton(); + void handleStateChange(); + void triggerEvent(EventType event); }; \ No newline at end of file diff --git a/examples/companion_radio/MyMesh.cpp b/examples/companion_radio/MyMesh.cpp index 6e9688a53..db40169f9 100644 --- a/examples/companion_radio/MyMesh.cpp +++ b/examples/companion_radio/MyMesh.cpp @@ -1,19 +1,83 @@ +#include "MyMesh.h" + #include // needed for PlatformIO #include -#include "MyMesh.h" + +#define CMD_APP_START 1 +#define CMD_SEND_TXT_MSG 2 +#define CMD_SEND_CHANNEL_TXT_MSG 3 +#define CMD_GET_CONTACTS 4 // with optional 'since' (for efficient sync) +#define CMD_GET_DEVICE_TIME 5 +#define CMD_SET_DEVICE_TIME 6 +#define CMD_SEND_SELF_ADVERT 7 +#define CMD_SET_ADVERT_NAME 8 +#define CMD_ADD_UPDATE_CONTACT 9 +#define CMD_SYNC_NEXT_MESSAGE 10 +#define CMD_SET_RADIO_PARAMS 11 +#define CMD_SET_RADIO_TX_POWER 12 +#define CMD_RESET_PATH 13 +#define CMD_SET_ADVERT_LATLON 14 +#define CMD_REMOVE_CONTACT 15 +#define CMD_SHARE_CONTACT 16 +#define CMD_EXPORT_CONTACT 17 +#define CMD_IMPORT_CONTACT 18 +#define CMD_REBOOT 19 +#define CMD_GET_BATTERY_VOLTAGE 20 +#define CMD_SET_TUNING_PARAMS 21 +#define CMD_DEVICE_QEURY 22 +#define CMD_EXPORT_PRIVATE_KEY 23 +#define CMD_IMPORT_PRIVATE_KEY 24 +#define CMD_SEND_RAW_DATA 25 +#define CMD_SEND_LOGIN 26 +#define CMD_SEND_STATUS_REQ 27 +#define CMD_HAS_CONNECTION 28 +#define CMD_LOGOUT 29 // 'Disconnect' +#define CMD_GET_CONTACT_BY_KEY 30 +#define CMD_GET_CHANNEL 31 +#define CMD_SET_CHANNEL 32 +#define CMD_SIGN_START 33 +#define CMD_SIGN_DATA 34 +#define CMD_SIGN_FINISH 35 +#define CMD_SEND_TRACE_PATH 36 +#define CMD_SET_DEVICE_PIN 37 +#define CMD_SET_OTHER_PARAMS 38 +#define CMD_SEND_TELEMETRY_REQ 39 +#define CMD_GET_CUSTOM_VARS 40 +#define CMD_SET_CUSTOM_VAR 41 + +#define RESP_CODE_OK 0 +#define RESP_CODE_ERR 1 +#define RESP_CODE_CONTACTS_START 2 // first reply to CMD_GET_CONTACTS +#define RESP_CODE_CONTACT 3 // multiple of these (after CMD_GET_CONTACTS) +#define RESP_CODE_END_OF_CONTACTS 4 // last reply to CMD_GET_CONTACTS +#define RESP_CODE_SELF_INFO 5 // reply to CMD_APP_START +#define RESP_CODE_SENT 6 // reply to CMD_SEND_TXT_MSG +#define RESP_CODE_CONTACT_MSG_RECV 7 // a reply to CMD_SYNC_NEXT_MESSAGE (ver < 3) +#define RESP_CODE_CHANNEL_MSG_RECV 8 // a reply to CMD_SYNC_NEXT_MESSAGE (ver < 3) +#define RESP_CODE_CURR_TIME 9 // a reply to CMD_GET_DEVICE_TIME +#define RESP_CODE_NO_MORE_MESSAGES 10 // a reply to CMD_SYNC_NEXT_MESSAGE +#define RESP_CODE_EXPORT_CONTACT 11 +#define RESP_CODE_BATTERY_VOLTAGE 12 // a reply to a CMD_GET_BATTERY_VOLTAGE +#define RESP_CODE_DEVICE_INFO 13 // a reply to CMD_DEVICE_QEURY +#define RESP_CODE_PRIVATE_KEY 14 // a reply to CMD_EXPORT_PRIVATE_KEY +#define RESP_CODE_DISABLED 15 +#define RESP_CODE_CONTACT_MSG_RECV_V3 16 // a reply to CMD_SYNC_NEXT_MESSAGE (ver >= 3) +#define RESP_CODE_CHANNEL_MSG_RECV_V3 17 // a reply to CMD_SYNC_NEXT_MESSAGE (ver >= 3) +#define RESP_CODE_CHANNEL_INFO 18 // a reply to CMD_GET_CHANNEL +#define RESP_CODE_SIGN_START 19 +#define RESP_CODE_SIGNATURE 20 +#define RESP_CODE_CUSTOM_VARS 21 #ifdef DISPLAY_CLASS - #include "UITask.h" +#include "UITask.h" #endif void MyMesh::loadMainIdentity() { - if (!_identity_store->load("_main", self_id)) - { + if (!_identity_store->load("_main", self_id)) { self_id = radio_new_identity(); // create new random identity int count = 0; - while (count < 10 && (self_id.pub_key[0] == 0x00 || self_id.pub_key[0] == 0xFF)) - { // reserved id hashes + while (count < 10 && (self_id.pub_key[0] == 0x00 || self_id.pub_key[0] == 0xFF)) { // reserved id hashes self_id = radio_new_identity(); count++; } @@ -28,18 +92,15 @@ bool MyMesh::saveMainIdentity(const mesh::LocalIdentity &identity) void MyMesh::loadContacts() { - if (_fs->exists("/contacts3")) - { + if (_fs->exists("/contacts3")) { #if defined(RP2040_PLATFORM) File file = _fs->open("/contacts3", "r"); #else File file = _fs->open("/contacts3"); #endif - if (file) - { + if (file) { bool full = false; - while (!full) - { + while (!full) { ContactInfo c; uint8_t pub_key[32]; uint8_t unused; @@ -79,14 +140,12 @@ void MyMesh::saveContacts() #else File file = _fs->open("/contacts3", "w", true); #endif - if (file) - { + if (file) { ContactsIterator iter; ContactInfo c; uint8_t unused = 0; - while (iter.hasNext(this, c)) - { + while (iter.hasNext(this, c)) { bool success = (file.write(c.id.pub_key, 32) == 32); success = success && (file.write((uint8_t *)&c.name, 32) == 32); success = success && (file.write(&c.type, 1) == 1); @@ -109,19 +168,16 @@ void MyMesh::saveContacts() void MyMesh::loadChannels() { - if (_fs->exists("/channels2")) - { + if (_fs->exists("/channels2")) { #if defined(RP2040_PLATFORM) File file = _fs->open("/channels2", "r"); #else File file = _fs->open("/channels2"); #endif - if (file) - { + if (file) { bool full = false; uint8_t channel_idx = 0; - while (!full) - { + while (!full) { ChannelDetails ch; uint8_t unused[4]; @@ -132,12 +188,10 @@ void MyMesh::loadChannels() if (!success) break; // EOF - if (setChannel(channel_idx, ch)) - { + if (setChannel(channel_idx, ch)) { channel_idx++; } - else - { + else { full = true; } } @@ -156,15 +210,13 @@ void MyMesh::saveChannels() #else File file = _fs->open("/channels2", "w", true); #endif - if (file) - { + if (file) { uint8_t channel_idx = 0; ChannelDetails ch; uint8_t unused[4]; memset(unused, 0, 4); - while (getChannel(channel_idx, ch)) - { + while (getChannel(channel_idx, ch)) { bool success = (file.write(unused, 4) == 4); success = success && (file.write((uint8_t *)ch.name, 32) == 32); success = success && (file.write((uint8_t *)ch.channel.secret, 32) == 32); @@ -187,15 +239,13 @@ int MyMesh::getBlobByKey(const uint8_t key[], int key_len, uint8_t dest_buf[]) mesh::Utils::toHex(fname, key, key_len); sprintf(path, "/bl/%s", fname); - if (_fs->exists(path)) - { + if (_fs->exists(path)) { #if defined(RP2040_PLATFORM) File f = _fs->open(path, "r"); #else File f = _fs->open(path); #endif - if (f) - { + if (f) { int len = f.read(dest_buf, 255); // currently MAX 255 byte blob len supported!! f.close(); return len; @@ -222,8 +272,7 @@ bool MyMesh::putBlobByKey(const uint8_t key[], int key_len, const uint8_t src_bu #else File f = _fs->open(path, "w", true); #endif - if (f) - { + if (f) { int n = f.write(src_buf, len); f.close(); if (n == len) @@ -294,8 +343,7 @@ void MyMesh::updateContactFromFrame(ContactInfo &contact, const uint8_t *frame, i += 32; memcpy(&contact.last_advert_timestamp, &frame[i], 4); i += 4; - if (i + 8 >= len) - { // optional fields + if (i + 8 >= len) { // optional fields memcpy(&contact.gps_lat, &frame[i], 4); i += 4; memcpy(&contact.gps_lon, &frame[i], 4); @@ -305,12 +353,10 @@ void MyMesh::updateContactFromFrame(ContactInfo &contact, const uint8_t *frame, void MyMesh::addToOfflineQueue(const uint8_t frame[], int len) { - if (offline_queue_len >= OFFLINE_QUEUE_SIZE) - { + if (offline_queue_len >= OFFLINE_QUEUE_SIZE) { MESH_DEBUG_PRINTLN("ERROR: offline_queue is full!"); } - else - { + else { offline_queue[offline_queue_len].len = len; memcpy(offline_queue[offline_queue_len].buf, frame, len); offline_queue_len++; @@ -318,14 +364,12 @@ void MyMesh::addToOfflineQueue(const uint8_t frame[], int len) } int MyMesh::getFromOfflineQueue(uint8_t frame[]) { - if (offline_queue_len > 0) - { // check offline queue + if (offline_queue_len > 0) { // check offline queue size_t len = offline_queue[0].len; // take from top of queue memcpy(frame, offline_queue[0].buf, len); offline_queue_len--; - for (int i = 0; i < offline_queue_len; i++) - { // delete top item from queue + for (int i = 0; i < offline_queue_len; i++) { // delete top item from queue offline_queue[i] = offline_queue[i + 1]; } return len; @@ -352,8 +396,7 @@ int MyMesh::calcRxDelay(float score, uint32_t air_time) const void MyMesh::logRxRaw(float snr, float rssi, const uint8_t raw[], int len) { - if (_serial->isConnected() && len + 3 <= MAX_FRAME_SIZE) - { + if (_serial->isConnected() && len + 3 <= MAX_FRAME_SIZE) { int i = 0; out_frame[i++] = PUSH_CODE_LOG_RX_DATA; out_frame[i++] = (int8_t)(snr * 4); @@ -372,21 +415,17 @@ bool MyMesh::isAutoAddEnabled() const void MyMesh::onDiscoveredContact(ContactInfo &contact, bool is_new) { - if (_serial->isConnected()) - { - if (!isAutoAddEnabled() && is_new) - { + if (_serial->isConnected()) { + if (!isAutoAddEnabled() && is_new) { writeContactRespFrame(PUSH_CODE_NEW_ADVERT, contact); } - else - { + else { out_frame[0] = PUSH_CODE_ADVERT; memcpy(&out_frame[1], contact.id.pub_key, PUB_KEY_SIZE); _serial->writeFrame(out_frame, 1 + PUB_KEY_SIZE); } } - else - { + else { #ifdef DISPLAY_CLASS ui_task.soundBuzzer(UIEventType::newContactMessage); #endif @@ -407,10 +446,8 @@ void MyMesh::onContactPathUpdated(const ContactInfo &contact) bool MyMesh::processAck(const uint8_t *data) { // see if matches any in a table - for (int i = 0; i < EXPECTED_ACK_TABLE_SIZE; i++) - { - if (memcmp(data, &expected_ack_table[i].ack, 4) == 0) - { // got an ACK from recipient + for (int i = 0; i < EXPECTED_ACK_TABLE_SIZE; i++) { + if (memcmp(data, &expected_ack_table[i].ack, 4) == 0) { // got an ACK from recipient out_frame[0] = PUSH_CODE_SEND_CONFIRMED; memcpy(&out_frame[1], data, 4); uint32_t trip_time = _ms->getMillis() - expected_ack_table[i].msg_sent; @@ -425,18 +462,17 @@ bool MyMesh::processAck(const uint8_t *data) return checkConnectionsAck(data); } -void MyMesh::queueMessage(const ContactInfo &from, uint8_t txt_type, mesh::Packet *pkt, uint32_t sender_timestamp, const uint8_t *extra, int extra_len, const char *text) +void MyMesh::queueMessage(const ContactInfo &from, uint8_t txt_type, mesh::Packet *pkt, + uint32_t sender_timestamp, const uint8_t *extra, int extra_len, const char *text) { int i = 0; - if (app_target_ver >= 3) - { + if (app_target_ver >= 3) { out_frame[i++] = RESP_CODE_CONTACT_MSG_RECV_V3; out_frame[i++] = (int8_t)(pkt->getSNR() * 4); out_frame[i++] = 0; // reserved1 out_frame[i++] = 0; // reserved2 } - else - { + else { out_frame[i++] = RESP_CODE_CONTACT_MSG_RECV; } memcpy(&out_frame[i], from.id.pub_key, 6); @@ -445,28 +481,24 @@ void MyMesh::queueMessage(const ContactInfo &from, uint8_t txt_type, mesh::Packe out_frame[i++] = txt_type; memcpy(&out_frame[i], &sender_timestamp, 4); i += 4; - if (extra_len > 0) - { + if (extra_len > 0) { memcpy(&out_frame[i], extra, extra_len); i += extra_len; } int tlen = strlen(text); // TODO: UTF-8 ?? - if (i + tlen > MAX_FRAME_SIZE) - { + if (i + tlen > MAX_FRAME_SIZE) { tlen = MAX_FRAME_SIZE - i; } memcpy(&out_frame[i], text, tlen); i += tlen; addToOfflineQueue(out_frame, i); - if (_serial->isConnected()) - { + if (_serial->isConnected()) { uint8_t frame[1]; frame[0] = PUSH_CODE_MSG_WAITING; // send push 'tickle' _serial->writeFrame(frame, 1); } - else - { + else { #ifdef DISPLAY_CLASS ui_task.soundBuzzer(UIEventType::contactMessage); #endif @@ -476,19 +508,22 @@ void MyMesh::queueMessage(const ContactInfo &from, uint8_t txt_type, mesh::Packe #endif } -void MyMesh::onMessageRecv(const ContactInfo &from, mesh::Packet *pkt, uint32_t sender_timestamp, const char *text) +void MyMesh::onMessageRecv(const ContactInfo &from, mesh::Packet *pkt, uint32_t sender_timestamp, + const char *text) { markConnectionActive(from); // in case this is from a server, and we have a connection queueMessage(from, TXT_TYPE_PLAIN, pkt, sender_timestamp, NULL, 0, text); } -void MyMesh::onCommandDataRecv(const ContactInfo &from, mesh::Packet *pkt, uint32_t sender_timestamp, const char *text) +void MyMesh::onCommandDataRecv(const ContactInfo &from, mesh::Packet *pkt, uint32_t sender_timestamp, + const char *text) { markConnectionActive(from); // in case this is from a server, and we have a connection queueMessage(from, TXT_TYPE_CLI_DATA, pkt, sender_timestamp, NULL, 0, text); } -void MyMesh::onSignedMessageRecv(const ContactInfo &from, mesh::Packet *pkt, uint32_t sender_timestamp, const uint8_t *sender_prefix, const char *text) +void MyMesh::onSignedMessageRecv(const ContactInfo &from, mesh::Packet *pkt, uint32_t sender_timestamp, + const uint8_t *sender_prefix, const char *text) { markConnectionActive(from); // from.sync_since change needs to be persisted @@ -496,18 +531,17 @@ void MyMesh::onSignedMessageRecv(const ContactInfo &from, mesh::Packet *pkt, uin queueMessage(from, TXT_TYPE_SIGNED_PLAIN, pkt, sender_timestamp, sender_prefix, 4, text); } -void MyMesh::onChannelMessageRecv(const mesh::GroupChannel &channel, mesh::Packet *pkt, uint32_t timestamp, const char *text) +void MyMesh::onChannelMessageRecv(const mesh::GroupChannel &channel, mesh::Packet *pkt, uint32_t timestamp, + const char *text) { int i = 0; - if (app_target_ver >= 3) - { + if (app_target_ver >= 3) { out_frame[i++] = RESP_CODE_CHANNEL_MSG_RECV_V3; out_frame[i++] = (int8_t)(pkt->getSNR() * 4); out_frame[i++] = 0; // reserved1 out_frame[i++] = 0; // reserved2 } - else - { + else { out_frame[i++] = RESP_CODE_CHANNEL_MSG_RECV; } @@ -518,22 +552,19 @@ void MyMesh::onChannelMessageRecv(const mesh::GroupChannel &channel, mesh::Packe memcpy(&out_frame[i], ×tamp, 4); i += 4; int tlen = strlen(text); // TODO: UTF-8 ?? - if (i + tlen > MAX_FRAME_SIZE) - { + if (i + tlen > MAX_FRAME_SIZE) { tlen = MAX_FRAME_SIZE - i; } memcpy(&out_frame[i], text, tlen); i += tlen; addToOfflineQueue(out_frame, i); - if (_serial->isConnected()) - { + if (_serial->isConnected()) { uint8_t frame[1]; frame[0] = PUSH_CODE_MSG_WAITING; // send push 'tickle' _serial->writeFrame(frame, 1); } - else - { + else { #ifdef DISPLAY_CLASS ui_task.soundBuzzer(UIEventType::channelMessage); #endif @@ -543,48 +574,42 @@ void MyMesh::onChannelMessageRecv(const mesh::GroupChannel &channel, mesh::Packe #endif } -uint8_t MyMesh::onContactRequest(const ContactInfo &contact, uint32_t sender_timestamp, const uint8_t *data, uint8_t len, uint8_t *reply) +uint8_t MyMesh::onContactRequest(const ContactInfo &contact, uint32_t sender_timestamp, const uint8_t *data, + uint8_t len, uint8_t *reply) { - if (data[0] == REQ_TYPE_GET_TELEMETRY_DATA) - { + if (data[0] == REQ_TYPE_GET_TELEMETRY_DATA) { uint8_t permissions = 0; uint8_t cp = contact.flags >> 1; // LSB used as 'favourite' bit (so only use upper bits) - if (_prefs.telemetry_mode_base == TELEM_MODE_ALLOW_ALL) - { + if (_prefs.telemetry_mode_base == TELEM_MODE_ALLOW_ALL) { permissions = TELEM_PERM_BASE; } - else if (_prefs.telemetry_mode_base == TELEM_MODE_ALLOW_FLAGS) - { + else if (_prefs.telemetry_mode_base == TELEM_MODE_ALLOW_FLAGS) { permissions = cp & TELEM_PERM_BASE; } - if (_prefs.telemetry_mode_loc == TELEM_MODE_ALLOW_ALL) - { + if (_prefs.telemetry_mode_loc == TELEM_MODE_ALLOW_ALL) { permissions |= TELEM_PERM_LOCATION; } - else if (_prefs.telemetry_mode_loc == TELEM_MODE_ALLOW_FLAGS) - { + else if (_prefs.telemetry_mode_loc == TELEM_MODE_ALLOW_FLAGS) { permissions |= cp & TELEM_PERM_LOCATION; } - if (_prefs.telemetry_mode_env == TELEM_MODE_ALLOW_ALL) - { + if (_prefs.telemetry_mode_env == TELEM_MODE_ALLOW_ALL) { permissions |= TELEM_PERM_ENVIRONMENT; } - else if (_prefs.telemetry_mode_env == TELEM_MODE_ALLOW_FLAGS) - { + else if (_prefs.telemetry_mode_env == TELEM_MODE_ALLOW_FLAGS) { permissions |= cp & TELEM_PERM_ENVIRONMENT; } - if (permissions & TELEM_PERM_BASE) - { // only respond if base permission bit is set + if (permissions & TELEM_PERM_BASE) { // only respond if base permission bit is set telemetry.reset(); telemetry.addVoltage(TELEM_CHANNEL_SELF, (float)board.getBattMilliVolts() / 1000.0f); // query other sensors -- target specific sensors.querySensors(permissions, telemetry); - memcpy(reply, &sender_timestamp, 4); // reflect sender_timestamp back in response packet (kind of like a 'tag') + memcpy(reply, &sender_timestamp, + 4); // reflect sender_timestamp back in response packet (kind of like a 'tag') uint8_t tlen = telemetry.getSize(); memcpy(&reply[4], telemetry.getBuffer(), tlen); @@ -599,24 +624,20 @@ void MyMesh::onContactResponse(const ContactInfo &contact, const uint8_t *data, uint32_t tag; memcpy(&tag, data, 4); - if (pending_login && memcmp(&pending_login, contact.id.pub_key, 4) == 0) - { // check for login response + if (pending_login && memcmp(&pending_login, contact.id.pub_key, 4) == 0) { // check for login response // yes, is response to pending sendLogin() pending_login = 0; int i = 0; - if (memcmp(&data[4], "OK", 2) == 0) - { // legacy Repeater login OK response + if (memcmp(&data[4], "OK", 2) == 0) { // legacy Repeater login OK response out_frame[i++] = PUSH_CODE_LOGIN_SUCCESS; out_frame[i++] = 0; // legacy: is_admin = false memcpy(&out_frame[i], contact.id.pub_key, 6); i += 6; // pub_key_prefix } - else if (data[4] == RESP_SERVER_LOGIN_OK) - { // new login response + else if (data[4] == RESP_SERVER_LOGIN_OK) { // new login response uint16_t keep_alive_secs = ((uint16_t)data[5]) * 16; - if (keep_alive_secs > 0) - { + if (keep_alive_secs > 0) { startConnection(contact, keep_alive_secs); } out_frame[i++] = PUSH_CODE_LOGIN_SUCCESS; @@ -626,8 +647,7 @@ void MyMesh::onContactResponse(const ContactInfo &contact, const uint8_t *data, memcpy(&out_frame[i], &tag, 4); i += 4; // NEW: include server timestamp } - else - { + else { out_frame[i++] = PUSH_CODE_LOGIN_FAIL; out_frame[i++] = 0; // reserved memcpy(&out_frame[i], contact.id.pub_key, 6); @@ -635,11 +655,11 @@ void MyMesh::onContactResponse(const ContactInfo &contact, const uint8_t *data, } _serial->writeFrame(out_frame, i); } - else if (len > 4 && // check for status response - pending_status && memcmp(&pending_status, contact.id.pub_key, 4) == 0 // legacy matching scheme - // FUTURE: tag == pending_status - ) - { + else if (len > 4 && // check for status response + pending_status && + memcmp(&pending_status, contact.id.pub_key, 4) == 0 // legacy matching scheme + // FUTURE: tag == pending_status + ) { pending_status = 0; int i = 0; @@ -651,8 +671,7 @@ void MyMesh::onContactResponse(const ContactInfo &contact, const uint8_t *data, i += (len - 4); _serial->writeFrame(out_frame, i); } - else if (len > 4 && tag == pending_telemetry) - { // check for telemetry response + else if (len > 4 && tag == pending_telemetry) { // check for telemetry response pending_telemetry = 0; int i = 0; @@ -668,8 +687,7 @@ void MyMesh::onContactResponse(const ContactInfo &contact, const uint8_t *data, void MyMesh::onRawDataRecv(mesh::Packet *packet) { - if (packet->payload_len + 4 > sizeof(out_frame)) - { + if (packet->payload_len + 4 > sizeof(out_frame)) { MESH_DEBUG_PRINTLN("onRawDataRecv(), payload_len too long: %d", packet->payload_len); return; } @@ -681,17 +699,16 @@ void MyMesh::onRawDataRecv(mesh::Packet *packet) memcpy(&out_frame[i], packet->payload, packet->payload_len); i += packet->payload_len; - if (_serial->isConnected()) - { + if (_serial->isConnected()) { _serial->writeFrame(out_frame, i); } - else - { + else { MESH_DEBUG_PRINTLN("onRawDataRecv(), data received while app offline"); } } -void MyMesh::onTraceRecv(mesh::Packet *packet, uint32_t tag, uint32_t auth_code, uint8_t flags, const uint8_t *path_snrs, const uint8_t *path_hashes, uint8_t path_len) +void MyMesh::onTraceRecv(mesh::Packet *packet, uint32_t tag, uint32_t auth_code, uint8_t flags, + const uint8_t *path_snrs, const uint8_t *path_hashes, uint8_t path_len) { int i = 0; out_frame[i++] = PUSH_CODE_TRACE_DATA; @@ -708,12 +725,10 @@ void MyMesh::onTraceRecv(mesh::Packet *packet, uint32_t tag, uint32_t auth_code, i += path_len; out_frame[i++] = (int8_t)(packet->getSNR() * 4); // extra/final SNR (to this node) - if (_serial->isConnected()) - { + if (_serial->isConnected()) { _serial->writeFrame(out_frame, i); } - else - { + else { MESH_DEBUG_PRINTLN("onTraceRecv(), data received while app offline"); } } @@ -725,16 +740,15 @@ uint32_t MyMesh::calcFloodTimeoutMillisFor(uint32_t pkt_airtime_millis) const uint32_t MyMesh::calcDirectTimeoutMillisFor(uint32_t pkt_airtime_millis, uint8_t path_len) const { return SEND_TIMEOUT_BASE_MILLIS + - ((pkt_airtime_millis * DIRECT_SEND_PERHOP_FACTOR + DIRECT_SEND_PERHOP_EXTRA_MILLIS) * (path_len + 1)); + ((pkt_airtime_millis * DIRECT_SEND_PERHOP_FACTOR + DIRECT_SEND_PERHOP_EXTRA_MILLIS) * + (path_len + 1)); } -void MyMesh::onSendTimeout() -{ -} +void MyMesh::onSendTimeout() {} MyMesh::MyMesh(mesh::Radio &radio, mesh::RNG &rng, mesh::RTCClock &rtc, SimpleMeshTables &tables) - : BaseChatMesh(radio, *new ArduinoMillis(), rng, rtc, *new StaticPoolPacketManager(16), tables), _serial(NULL), - telemetry(MAX_PACKET_PAYLOAD - 4) + : BaseChatMesh(radio, *new ArduinoMillis(), rng, rtc, *new StaticPoolPacketManager(16), tables), + _serial(NULL), telemetry(MAX_PACKET_PAYLOAD - 4) { _iter_started = false; offline_queue_len = 0; @@ -764,8 +778,7 @@ void MyMesh::loadPrefsInt(const char *filename) #else File file = _fs->open(filename); #endif - if (file) - { + if (file) { uint8_t pad[8]; file.read((uint8_t *)&_prefs.airtime_factor, sizeof(float)); // 0 @@ -828,36 +841,30 @@ void MyMesh::begin(FILESYSTEM &fs, bool has_display) #endif // load persisted prefs - if (_fs->exists("/new_prefs")) - { + if (_fs->exists("/new_prefs")) { loadPrefsInt("/new_prefs"); // new filename } - else if (_fs->exists("/node_prefs")) - { + else if (_fs->exists("/node_prefs")) { loadPrefsInt("/node_prefs"); savePrefs(); // save to new filename _fs->remove("/node_prefs"); // remove old } #ifdef BLE_PIN_CODE - if (_prefs.ble_pin == 0) - { + if (_prefs.ble_pin == 0) { #ifdef DISPLAY_CLASS - if (has_display) - { + if (has_display) { StdRNG rng; _active_ble_pin = rng.nextInt(100000, 999999); // random pin each session } - else - { + else { _active_ble_pin = BLE_PIN_CODE; // otherwise static pin } #else _active_ble_pin = BLE_PIN_CODE; // otherwise static pin #endif } - else - { + else { _active_ble_pin = _prefs.ble_pin; } #else @@ -875,12 +882,18 @@ void MyMesh::begin(FILESYSTEM &fs, bool has_display) radio_set_tx_power(_prefs.tx_power_dbm); } -const char *MyMesh::getNodeName() { return _prefs.node_name; } +const char *MyMesh::getNodeName() +{ + return _prefs.node_name; +} NodePrefs *MyMesh::getNodePrefs() { return &_prefs; } -uint32_t MyMesh::getBLEPin() { return _active_ble_pin; } +uint32_t MyMesh::getBLEPin() +{ + return _active_ble_pin; +} void MyMesh::startInterface(BaseSerialInterface &serial) { @@ -898,8 +911,7 @@ void MyMesh::savePrefs() #else File file = _fs->open("/new_prefs", "w", true); #endif - if (file) - { + if (file) { uint8_t pad[8]; memset(pad, 0, sizeof(pad)); @@ -928,9 +940,8 @@ void MyMesh::savePrefs() void MyMesh::handleCmdFrame(size_t len) { - if (cmd_frame[0] == CMD_DEVICE_QEURY && len >= 2) - { // sent when app establishes connection - app_target_ver = cmd_frame[1]; // which version of protocol does app understand + if (cmd_frame[0] == CMD_DEVICE_QEURY && len >= 2) { // sent when app establishes connection + app_target_ver = cmd_frame[1]; // which version of protocol does app understand int i = 0; out_frame[i++] = RESP_CODE_DEVICE_INFO; @@ -948,8 +959,8 @@ void MyMesh::handleCmdFrame(size_t len) i += 20; _serial->writeFrame(out_frame, i); } - else if (cmd_frame[0] == CMD_APP_START && len >= 8) - { // sent when app establishes connection, respond with node ID + else if (cmd_frame[0] == CMD_APP_START && + len >= 8) { // sent when app establishes connection, respond with node ID // cmd_frame[1..7] reserved future char *app_name = (char *)&cmd_frame[8]; cmd_frame[len] = 0; // make app_name null terminated @@ -971,9 +982,10 @@ void MyMesh::handleCmdFrame(size_t len) i += 4; memcpy(&out_frame[i], &lon, 4); i += 4; - out_frame[i++] = 0; // reserved - out_frame[i++] = 0; // reserved - out_frame[i++] = (_prefs.telemetry_mode_env << 4) | (_prefs.telemetry_mode_loc << 2) | (_prefs.telemetry_mode_base); // v5+ + out_frame[i++] = 0; // reserved + out_frame[i++] = 0; // reserved + out_frame[i++] = (_prefs.telemetry_mode_env << 4) | (_prefs.telemetry_mode_loc << 2) | + (_prefs.telemetry_mode_base); // v5+ out_frame[i++] = _prefs.manual_add_contacts; uint32_t freq = _prefs.freq * 1000; @@ -990,8 +1002,7 @@ void MyMesh::handleCmdFrame(size_t len) i += tlen; _serial->writeFrame(out_frame, i); } - else if (cmd_frame[0] == CMD_SEND_TXT_MSG && len >= 14) - { + else if (cmd_frame[0] == CMD_SEND_TXT_MSG && len >= 14) { int i = 1; uint8_t txt_type = cmd_frame[i++]; uint8_t attempt = cmd_frame[i++]; @@ -1001,32 +1012,26 @@ void MyMesh::handleCmdFrame(size_t len) uint8_t *pub_key_prefix = &cmd_frame[i]; i += 6; ContactInfo *recipient = lookupContactByPubKey(pub_key_prefix, 6); - if (recipient && (txt_type == TXT_TYPE_PLAIN || txt_type == TXT_TYPE_CLI_DATA)) - { + if (recipient && (txt_type == TXT_TYPE_PLAIN || txt_type == TXT_TYPE_CLI_DATA)) { char *text = (char *)&cmd_frame[i]; int tlen = len - i; uint32_t est_timeout; text[tlen] = 0; // ensure null int result; uint32_t expected_ack; - if (txt_type == TXT_TYPE_CLI_DATA) - { + if (txt_type == TXT_TYPE_CLI_DATA) { result = sendCommandData(*recipient, msg_timestamp, attempt, text, est_timeout); expected_ack = 0; // no Ack expected } - else - { + else { result = sendMessage(*recipient, msg_timestamp, attempt, text, expected_ack, est_timeout); } // TODO: add expected ACK to table - if (result == MSG_SEND_FAILED) - { + if (result == MSG_SEND_FAILED) { writeErrFrame(ERR_CODE_TABLE_FULL); } - else - { - if (expected_ack) - { + else { + if (expected_ack) { expected_ack_table[next_ack_idx].msg_sent = _ms->getMillis(); // add to circular table expected_ack_table[next_ack_idx].ack = expected_ack; next_ack_idx = (next_ack_idx + 1) % EXPECTED_ACK_TABLE_SIZE; @@ -1039,13 +1044,13 @@ void MyMesh::handleCmdFrame(size_t len) _serial->writeFrame(out_frame, 10); } } - else - { - writeErrFrame(recipient == NULL ? ERR_CODE_NOT_FOUND : ERR_CODE_UNSUPPORTED_CMD); // unknown recipient, or unsuported TXT_TYPE_* + else { + writeErrFrame(recipient == NULL + ? ERR_CODE_NOT_FOUND + : ERR_CODE_UNSUPPORTED_CMD); // unknown recipient, or unsuported TXT_TYPE_* } } - else if (cmd_frame[0] == CMD_SEND_CHANNEL_TXT_MSG) - { // send GroupChannel msg + else if (cmd_frame[0] == CMD_SEND_CHANNEL_TXT_MSG) { // send GroupChannel msg int i = 1; uint8_t txt_type = cmd_frame[i++]; // should be TXT_TYPE_PLAIN uint8_t channel_idx = cmd_frame[i++]; @@ -1054,38 +1059,29 @@ void MyMesh::handleCmdFrame(size_t len) i += 4; const char *text = (char *)&cmd_frame[i]; - if (txt_type != TXT_TYPE_PLAIN) - { + if (txt_type != TXT_TYPE_PLAIN) { writeErrFrame(ERR_CODE_UNSUPPORTED_CMD); } - else - { + else { ChannelDetails channel; bool success = getChannel(channel_idx, channel); - if (success && sendGroupMessage(msg_timestamp, channel.channel, _prefs.node_name, text, len - i)) - { + if (success && sendGroupMessage(msg_timestamp, channel.channel, _prefs.node_name, text, len - i)) { writeOKFrame(); } - else - { + else { writeErrFrame(ERR_CODE_NOT_FOUND); // bad channel_idx } } } - else if (cmd_frame[0] == CMD_GET_CONTACTS) - { // get Contact list - if (_iter_started) - { + else if (cmd_frame[0] == CMD_GET_CONTACTS) { // get Contact list + if (_iter_started) { writeErrFrame(ERR_CODE_BAD_STATE); // iterator is currently busy } - else - { - if (len >= 5) - { // has optional 'since' param + else { + if (len >= 5) { // has optional 'since' param memcpy(&_iter_filter_since, &cmd_frame[1], 4); } - else - { + else { _iter_filter_since = 0; } @@ -1101,8 +1097,7 @@ void MyMesh::handleCmdFrame(size_t len) _most_recent_lastmod = 0; } } - else if (cmd_frame[0] == CMD_SET_ADVERT_NAME && len >= 2) - { + else if (cmd_frame[0] == CMD_SET_ADVERT_NAME && len >= 2) { int nlen = len - 1; if (nlen > sizeof(_prefs.node_name) - 1) nlen = sizeof(_prefs.node_name) - 1; // max len @@ -1111,169 +1106,134 @@ void MyMesh::handleCmdFrame(size_t len) savePrefs(); writeOKFrame(); } - else if (cmd_frame[0] == CMD_SET_ADVERT_LATLON && len >= 9) - { + else if (cmd_frame[0] == CMD_SET_ADVERT_LATLON && len >= 9) { int32_t lat, lon, alt = 0; memcpy(&lat, &cmd_frame[1], 4); memcpy(&lon, &cmd_frame[5], 4); - if (len >= 13) - { + if (len >= 13) { memcpy(&alt, &cmd_frame[9], 4); // for FUTURE support } - if (lat <= 90 * 1E6 && lat >= -90 * 1E6 && lon <= 180 * 1E6 && lon >= -180 * 1E6) - { + if (lat <= 90 * 1E6 && lat >= -90 * 1E6 && lon <= 180 * 1E6 && lon >= -180 * 1E6) { sensors.node_lat = ((double)lat) / 1000000.0; sensors.node_lon = ((double)lon) / 1000000.0; savePrefs(); writeOKFrame(); } - else - { + else { writeErrFrame(ERR_CODE_ILLEGAL_ARG); // invalid geo coordinate } } - else if (cmd_frame[0] == CMD_GET_DEVICE_TIME) - { + else if (cmd_frame[0] == CMD_GET_DEVICE_TIME) { uint8_t reply[5]; reply[0] = RESP_CODE_CURR_TIME; uint32_t now = getRTCClock()->getCurrentTime(); memcpy(&reply[1], &now, 4); _serial->writeFrame(reply, 5); } - else if (cmd_frame[0] == CMD_SET_DEVICE_TIME && len >= 5) - { + else if (cmd_frame[0] == CMD_SET_DEVICE_TIME && len >= 5) { uint32_t secs; memcpy(&secs, &cmd_frame[1], 4); uint32_t curr = getRTCClock()->getCurrentTime(); - if (secs >= curr) - { + if (secs >= curr) { getRTCClock()->setCurrentTime(secs); writeOKFrame(); } - else - { + else { writeErrFrame(ERR_CODE_ILLEGAL_ARG); } } - else if (cmd_frame[0] == CMD_SEND_SELF_ADVERT) - { + else if (cmd_frame[0] == CMD_SEND_SELF_ADVERT) { auto pkt = createSelfAdvert(_prefs.node_name, sensors.node_lat, sensors.node_lon); - if (pkt) - { - if (len >= 2 && cmd_frame[1] == 1) - { // optional param (1 = flood, 0 = zero hop) + if (pkt) { + if (len >= 2 && cmd_frame[1] == 1) { // optional param (1 = flood, 0 = zero hop) sendFlood(pkt); } - else - { + else { sendZeroHop(pkt); } writeOKFrame(); } - else - { + else { writeErrFrame(ERR_CODE_TABLE_FULL); } } - else if (cmd_frame[0] == CMD_RESET_PATH && len >= 1 + 32) - { + else if (cmd_frame[0] == CMD_RESET_PATH && len >= 1 + 32) { uint8_t *pub_key = &cmd_frame[1]; ContactInfo *recipient = lookupContactByPubKey(pub_key, PUB_KEY_SIZE); - if (recipient) - { + if (recipient) { recipient->out_path_len = -1; // recipient->lastmod = ?? shouldn't be needed, app already has this version of contact dirty_contacts_expiry = futureMillis(LAZY_CONTACTS_WRITE_DELAY); writeOKFrame(); } - else - { + else { writeErrFrame(ERR_CODE_NOT_FOUND); // unknown contact } } - else if (cmd_frame[0] == CMD_ADD_UPDATE_CONTACT && len >= 1 + 32 + 2 + 1) - { + else if (cmd_frame[0] == CMD_ADD_UPDATE_CONTACT && len >= 1 + 32 + 2 + 1) { uint8_t *pub_key = &cmd_frame[1]; ContactInfo *recipient = lookupContactByPubKey(pub_key, PUB_KEY_SIZE); - if (recipient) - { + if (recipient) { updateContactFromFrame(*recipient, cmd_frame, len); // recipient->lastmod = ?? shouldn't be needed, app already has this version of contact dirty_contacts_expiry = futureMillis(LAZY_CONTACTS_WRITE_DELAY); writeOKFrame(); } - else - { + else { ContactInfo contact; updateContactFromFrame(contact, cmd_frame, len); contact.lastmod = getRTCClock()->getCurrentTime(); contact.sync_since = 0; - if (addContact(contact)) - { + if (addContact(contact)) { dirty_contacts_expiry = futureMillis(LAZY_CONTACTS_WRITE_DELAY); writeOKFrame(); } - else - { + else { writeErrFrame(ERR_CODE_TABLE_FULL); } } } - else if (cmd_frame[0] == CMD_REMOVE_CONTACT) - { + else if (cmd_frame[0] == CMD_REMOVE_CONTACT) { uint8_t *pub_key = &cmd_frame[1]; ContactInfo *recipient = lookupContactByPubKey(pub_key, PUB_KEY_SIZE); - if (recipient && removeContact(*recipient)) - { + if (recipient && removeContact(*recipient)) { dirty_contacts_expiry = futureMillis(LAZY_CONTACTS_WRITE_DELAY); writeOKFrame(); } - else - { + else { writeErrFrame(ERR_CODE_NOT_FOUND); // not found, or unable to remove } } - else if (cmd_frame[0] == CMD_SHARE_CONTACT) - { + else if (cmd_frame[0] == CMD_SHARE_CONTACT) { uint8_t *pub_key = &cmd_frame[1]; ContactInfo *recipient = lookupContactByPubKey(pub_key, PUB_KEY_SIZE); - if (recipient) - { - if (shareContactZeroHop(*recipient)) - { + if (recipient) { + if (shareContactZeroHop(*recipient)) { writeOKFrame(); } - else - { + else { writeErrFrame(ERR_CODE_TABLE_FULL); // unable to send } } - else - { + else { writeErrFrame(ERR_CODE_NOT_FOUND); } } - else if (cmd_frame[0] == CMD_GET_CONTACT_BY_KEY) - { + else if (cmd_frame[0] == CMD_GET_CONTACT_BY_KEY) { uint8_t *pub_key = &cmd_frame[1]; ContactInfo *contact = lookupContactByPubKey(pub_key, PUB_KEY_SIZE); - if (contact) - { + if (contact) { writeContactRespFrame(RESP_CODE_CONTACT, *contact); } - else - { + else { writeErrFrame(ERR_CODE_NOT_FOUND); // not found } } - else if (cmd_frame[0] == CMD_EXPORT_CONTACT) - { - if (len < 1 + PUB_KEY_SIZE) - { + else if (cmd_frame[0] == CMD_EXPORT_CONTACT) { + if (len < 1 + PUB_KEY_SIZE) { // export SELF auto pkt = createSelfAdvert(_prefs.node_name, sensors.node_lat, sensors.node_lon); - if (pkt) - { + if (pkt) { pkt->header |= ROUTE_TYPE_FLOOD; // would normally be sent in this mode out_frame[0] = RESP_CODE_EXPORT_CONTACT; @@ -1281,56 +1241,45 @@ void MyMesh::handleCmdFrame(size_t len) releasePacket(pkt); // undo the obtainNewPacket() _serial->writeFrame(out_frame, out_len + 1); } - else - { + else { writeErrFrame(ERR_CODE_TABLE_FULL); // Error } } - else - { + else { uint8_t *pub_key = &cmd_frame[1]; ContactInfo *recipient = lookupContactByPubKey(pub_key, PUB_KEY_SIZE); uint8_t out_len; - if (recipient && (out_len = exportContact(*recipient, &out_frame[1])) > 0) - { + if (recipient && (out_len = exportContact(*recipient, &out_frame[1])) > 0) { out_frame[0] = RESP_CODE_EXPORT_CONTACT; _serial->writeFrame(out_frame, out_len + 1); } - else - { + else { writeErrFrame(ERR_CODE_NOT_FOUND); // not found } } } - else if (cmd_frame[0] == CMD_IMPORT_CONTACT && len > 2 + 32 + 64) - { - if (importContact(&cmd_frame[1], len - 1)) - { + else if (cmd_frame[0] == CMD_IMPORT_CONTACT && len > 2 + 32 + 64) { + if (importContact(&cmd_frame[1], len - 1)) { writeOKFrame(); } - else - { + else { writeErrFrame(ERR_CODE_ILLEGAL_ARG); } } - else if (cmd_frame[0] == CMD_SYNC_NEXT_MESSAGE) - { + else if (cmd_frame[0] == CMD_SYNC_NEXT_MESSAGE) { int out_len; - if ((out_len = getFromOfflineQueue(out_frame)) > 0) - { + if ((out_len = getFromOfflineQueue(out_frame)) > 0) { _serial->writeFrame(out_frame, out_len); #ifdef DISPLAY_CLASS ui_task.msgRead(offline_queue_len); #endif } - else - { + else { out_frame[0] = RESP_CODE_NO_MORE_MESSAGES; _serial->writeFrame(out_frame, 1); } } - else if (cmd_frame[0] == CMD_SET_RADIO_PARAMS) - { + else if (cmd_frame[0] == CMD_SET_RADIO_PARAMS) { int i = 1; uint32_t freq; memcpy(&freq, &cmd_frame[i], 4); @@ -1341,8 +1290,8 @@ void MyMesh::handleCmdFrame(size_t len) uint8_t sf = cmd_frame[i++]; uint8_t cr = cmd_frame[i++]; - if (freq >= 300000 && freq <= 2500000 && sf >= 7 && sf <= 12 && cr >= 5 && cr <= 8 && bw >= 7000 && bw <= 500000) - { + if (freq >= 300000 && freq <= 2500000 && sf >= 7 && sf <= 12 && cr >= 5 && cr <= 8 && bw >= 7000 && + bw <= 500000) { _prefs.sf = sf; _prefs.cr = cr; _prefs.freq = (float)freq / 1000.0; @@ -1350,32 +1299,29 @@ void MyMesh::handleCmdFrame(size_t len) savePrefs(); radio_set_params(_prefs.freq, _prefs.bw, _prefs.sf, _prefs.cr); - MESH_DEBUG_PRINTLN("OK: CMD_SET_RADIO_PARAMS: f=%d, bw=%d, sf=%d, cr=%d", freq, bw, (uint32_t)sf, (uint32_t)cr); + MESH_DEBUG_PRINTLN("OK: CMD_SET_RADIO_PARAMS: f=%d, bw=%d, sf=%d, cr=%d", freq, bw, (uint32_t)sf, + (uint32_t)cr); writeOKFrame(); } - else - { - MESH_DEBUG_PRINTLN("Error: CMD_SET_RADIO_PARAMS: f=%d, bw=%d, sf=%d, cr=%d", freq, bw, (uint32_t)sf, (uint32_t)cr); + else { + MESH_DEBUG_PRINTLN("Error: CMD_SET_RADIO_PARAMS: f=%d, bw=%d, sf=%d, cr=%d", freq, bw, (uint32_t)sf, + (uint32_t)cr); writeErrFrame(ERR_CODE_ILLEGAL_ARG); } } - else if (cmd_frame[0] == CMD_SET_RADIO_TX_POWER) - { - if (cmd_frame[1] > MAX_LORA_TX_POWER) - { + else if (cmd_frame[0] == CMD_SET_RADIO_TX_POWER) { + if (cmd_frame[1] > MAX_LORA_TX_POWER) { writeErrFrame(ERR_CODE_ILLEGAL_ARG); } - else - { + else { _prefs.tx_power_dbm = cmd_frame[1]; savePrefs(); radio_set_tx_power(_prefs.tx_power_dbm); writeOKFrame(); } } - else if (cmd_frame[0] == CMD_SET_TUNING_PARAMS) - { + else if (cmd_frame[0] == CMD_SET_TUNING_PARAMS) { int i = 1; uint32_t rx, af; memcpy(&rx, &cmd_frame[i], 4); @@ -1387,11 +1333,9 @@ void MyMesh::handleCmdFrame(size_t len) savePrefs(); writeOKFrame(); } - else if (cmd_frame[0] == CMD_SET_OTHER_PARAMS) - { + else if (cmd_frame[0] == CMD_SET_OTHER_PARAMS) { _prefs.manual_add_contacts = cmd_frame[1]; - if (len >= 3) - { + if (len >= 3) { _prefs.telemetry_mode_base = cmd_frame[2] & 0x03; // v5+ _prefs.telemetry_mode_loc = (cmd_frame[2] >> 2) & 0x03; _prefs.telemetry_mode_env = (cmd_frame[2] >> 4) & 0x03; @@ -1399,24 +1343,20 @@ void MyMesh::handleCmdFrame(size_t len) savePrefs(); writeOKFrame(); } - else if (cmd_frame[0] == CMD_REBOOT && memcmp(&cmd_frame[1], "reboot", 6) == 0) - { - if (dirty_contacts_expiry) - { // is there are pending dirty contacts write needed? + else if (cmd_frame[0] == CMD_REBOOT && memcmp(&cmd_frame[1], "reboot", 6) == 0) { + if (dirty_contacts_expiry) { // is there are pending dirty contacts write needed? saveContacts(); } board.reboot(); } - else if (cmd_frame[0] == CMD_GET_BATTERY_VOLTAGE) - { + else if (cmd_frame[0] == CMD_GET_BATTERY_VOLTAGE) { uint8_t reply[3]; reply[0] = RESP_CODE_BATTERY_VOLTAGE; uint16_t battery_millivolts = board.getBattMilliVolts(); memcpy(&reply[1], &battery_millivolts, 2); _serial->writeFrame(reply, 3); } - else if (cmd_frame[0] == CMD_EXPORT_PRIVATE_KEY) - { + else if (cmd_frame[0] == CMD_EXPORT_PRIVATE_KEY) { #if ENABLE_PRIVATE_KEY_EXPORT uint8_t reply[65]; reply[0] = RESP_CODE_PRIVATE_KEY; @@ -1426,64 +1366,52 @@ void MyMesh::handleCmdFrame(size_t len) writeDisabledFrame(); #endif } - else if (cmd_frame[0] == CMD_IMPORT_PRIVATE_KEY && len >= 65) - { + else if (cmd_frame[0] == CMD_IMPORT_PRIVATE_KEY && len >= 65) { #if ENABLE_PRIVATE_KEY_IMPORT mesh::LocalIdentity identity; identity.readFrom(&cmd_frame[1], 64); - if (saveMainIdentity(identity)) - { + if (saveMainIdentity(identity)) { self_id = identity; writeOKFrame(); } - else - { + else { writeErrFrame(ERR_CODE_FILE_IO_ERROR); } #else writeDisabledFrame(); #endif } - else if (cmd_frame[0] == CMD_SEND_RAW_DATA && len >= 6) - { + else if (cmd_frame[0] == CMD_SEND_RAW_DATA && len >= 6) { int i = 1; int8_t path_len = cmd_frame[i++]; - if (path_len >= 0 && i + path_len + 4 <= len) - { // minimum 4 byte payload + if (path_len >= 0 && i + path_len + 4 <= len) { // minimum 4 byte payload uint8_t *path = &cmd_frame[i]; i += path_len; auto pkt = createRawData(&cmd_frame[i], len - i); - if (pkt) - { + if (pkt) { sendDirect(pkt, path, path_len); writeOKFrame(); } - else - { + else { writeErrFrame(ERR_CODE_TABLE_FULL); } } - else - { + else { writeErrFrame(ERR_CODE_UNSUPPORTED_CMD); // flood, not supported (yet) } } - else if (cmd_frame[0] == CMD_SEND_LOGIN && len >= 1 + PUB_KEY_SIZE) - { + else if (cmd_frame[0] == CMD_SEND_LOGIN && len >= 1 + PUB_KEY_SIZE) { uint8_t *pub_key = &cmd_frame[1]; ContactInfo *recipient = lookupContactByPubKey(pub_key, PUB_KEY_SIZE); char *password = (char *)&cmd_frame[1 + PUB_KEY_SIZE]; cmd_frame[len] = 0; // ensure null terminator in password - if (recipient) - { + if (recipient) { uint32_t est_timeout; int result = sendLogin(*recipient, password, est_timeout); - if (result == MSG_SEND_FAILED) - { + if (result == MSG_SEND_FAILED) { writeErrFrame(ERR_CODE_TABLE_FULL); } - else - { + else { pending_telemetry = pending_status = 0; memcpy(&pending_login, recipient->id.pub_key, 4); // match this to onContactResponse() out_frame[0] = RESP_CODE_SENT; @@ -1493,25 +1421,20 @@ void MyMesh::handleCmdFrame(size_t len) _serial->writeFrame(out_frame, 10); } } - else - { + 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]; ContactInfo *recipient = lookupContactByPubKey(pub_key, PUB_KEY_SIZE); - if (recipient) - { + if (recipient) { uint32_t tag, est_timeout; int result = sendRequest(*recipient, REQ_TYPE_GET_STATUS, tag, est_timeout); - if (result == MSG_SEND_FAILED) - { + if (result == MSG_SEND_FAILED) { writeErrFrame(ERR_CODE_TABLE_FULL); } - else - { + else { pending_telemetry = pending_login = 0; // FUTURE: pending_status = tag; // match this in onContactResponse() memcpy(&pending_status, recipient->id.pub_key, 4); // legacy matching scheme @@ -1522,25 +1445,20 @@ void MyMesh::handleCmdFrame(size_t len) _serial->writeFrame(out_frame, 10); } } - else - { + else { writeErrFrame(ERR_CODE_NOT_FOUND); // contact not found } } - else if (cmd_frame[0] == CMD_SEND_TELEMETRY_REQ && len >= 4 + PUB_KEY_SIZE) - { + else if (cmd_frame[0] == CMD_SEND_TELEMETRY_REQ && len >= 4 + PUB_KEY_SIZE) { uint8_t *pub_key = &cmd_frame[4]; ContactInfo *recipient = lookupContactByPubKey(pub_key, PUB_KEY_SIZE); - if (recipient) - { + if (recipient) { uint32_t tag, est_timeout; int result = sendRequest(*recipient, REQ_TYPE_GET_TELEMETRY_DATA, tag, est_timeout); - if (result == MSG_SEND_FAILED) - { + if (result == MSG_SEND_FAILED) { writeErrFrame(ERR_CODE_TABLE_FULL); } - else - { + else { pending_status = pending_login = 0; pending_telemetry = tag; // match this in onContactResponse() out_frame[0] = RESP_CODE_SENT; @@ -1550,35 +1468,28 @@ void MyMesh::handleCmdFrame(size_t len) _serial->writeFrame(out_frame, 10); } } - else - { + else { writeErrFrame(ERR_CODE_NOT_FOUND); // contact not found } } - else if (cmd_frame[0] == CMD_HAS_CONNECTION && len >= 1 + PUB_KEY_SIZE) - { + else if (cmd_frame[0] == CMD_HAS_CONNECTION && len >= 1 + PUB_KEY_SIZE) { uint8_t *pub_key = &cmd_frame[1]; - if (hasConnectionTo(pub_key)) - { + if (hasConnectionTo(pub_key)) { writeOKFrame(); } - else - { + else { writeErrFrame(ERR_CODE_NOT_FOUND); } } - else if (cmd_frame[0] == CMD_LOGOUT && len >= 1 + PUB_KEY_SIZE) - { + else if (cmd_frame[0] == CMD_LOGOUT && len >= 1 + PUB_KEY_SIZE) { uint8_t *pub_key = &cmd_frame[1]; stopConnection(pub_key); writeOKFrame(); } - else if (cmd_frame[0] == CMD_GET_CHANNEL && len >= 2) - { + else if (cmd_frame[0] == CMD_GET_CHANNEL && len >= 2) { uint8_t channel_idx = cmd_frame[1]; ChannelDetails channel; - if (getChannel(channel_idx, channel)) - { + if (getChannel(channel_idx, channel)) { int i = 0; out_frame[i++] = RESP_CODE_CHANNEL_INFO; out_frame[i++] = channel_idx; @@ -1588,64 +1499,52 @@ void MyMesh::handleCmdFrame(size_t len) i += 16; // NOTE: only 128-bit supported _serial->writeFrame(out_frame, i); } - else - { + else { writeErrFrame(ERR_CODE_NOT_FOUND); } } - else if (cmd_frame[0] == CMD_SET_CHANNEL && len >= 2 + 32 + 32) - { + else if (cmd_frame[0] == CMD_SET_CHANNEL && len >= 2 + 32 + 32) { writeErrFrame(ERR_CODE_UNSUPPORTED_CMD); // not supported (yet) } - else if (cmd_frame[0] == CMD_SET_CHANNEL && len >= 2 + 32 + 16) - { + else if (cmd_frame[0] == CMD_SET_CHANNEL && len >= 2 + 32 + 16) { uint8_t channel_idx = cmd_frame[1]; ChannelDetails channel; StrHelper::strncpy(channel.name, (char *)&cmd_frame[2], 32); memset(channel.channel.secret, 0, sizeof(channel.channel.secret)); memcpy(channel.channel.secret, &cmd_frame[2 + 32], 16); // NOTE: only 128-bit supported - if (setChannel(channel_idx, channel)) - { + if (setChannel(channel_idx, channel)) { saveChannels(); writeOKFrame(); } - else - { + else { writeErrFrame(ERR_CODE_NOT_FOUND); // bad channel_idx } } - else if (cmd_frame[0] == CMD_SIGN_START) - { + else if (cmd_frame[0] == CMD_SIGN_START) { out_frame[0] = RESP_CODE_SIGN_START; out_frame[1] = 0; // reserved uint32_t len = MAX_SIGN_DATA_LEN; memcpy(&out_frame[2], &len, 4); _serial->writeFrame(out_frame, 6); - if (sign_data) - { + if (sign_data) { free(sign_data); } sign_data = (uint8_t *)malloc(MAX_SIGN_DATA_LEN); sign_data_len = 0; } - else if (cmd_frame[0] == CMD_SIGN_DATA && len > 1) - { - if (sign_data == NULL || sign_data_len + (len - 1) > MAX_SIGN_DATA_LEN) - { + else if (cmd_frame[0] == CMD_SIGN_DATA && len > 1) { + if (sign_data == NULL || sign_data_len + (len - 1) > MAX_SIGN_DATA_LEN) { writeErrFrame(sign_data == NULL ? ERR_CODE_BAD_STATE : ERR_CODE_TABLE_FULL); // error: too long } - else - { + else { memcpy(&sign_data[sign_data_len], &cmd_frame[1], len - 1); sign_data_len += (len - 1); writeOKFrame(); } } - else if (cmd_frame[0] == CMD_SIGN_FINISH) - { - if (sign_data) - { + else if (cmd_frame[0] == CMD_SIGN_FINISH) { + if (sign_data) { self_id.sign(&out_frame[1], sign_data, sign_data_len); free(sign_data); // don't need sign_data now @@ -1654,19 +1553,16 @@ void MyMesh::handleCmdFrame(size_t len) out_frame[0] = RESP_CODE_SIGNATURE; _serial->writeFrame(out_frame, 1 + SIGNATURE_SIZE); } - else - { + else { writeErrFrame(ERR_CODE_BAD_STATE); } } - else if (cmd_frame[0] == CMD_SEND_TRACE_PATH && len > 10 && len - 10 < MAX_PATH_SIZE) - { + else if (cmd_frame[0] == CMD_SEND_TRACE_PATH && len > 10 && len - 10 < MAX_PATH_SIZE) { uint32_t tag, auth; memcpy(&tag, &cmd_frame[1], 4); memcpy(&auth, &cmd_frame[5], 4); auto pkt = createTrace(tag, auth, cmd_frame[9]); - if (pkt) - { + if (pkt) { uint8_t path_len = len - 10; sendDirect(pkt, &cmd_frame[10], path_len); @@ -1679,38 +1575,31 @@ void MyMesh::handleCmdFrame(size_t len) memcpy(&out_frame[6], &est_timeout, 4); _serial->writeFrame(out_frame, 10); } - else - { + else { writeErrFrame(ERR_CODE_TABLE_FULL); } } - else if (cmd_frame[0] == CMD_SET_DEVICE_PIN && len >= 5) - { + else if (cmd_frame[0] == CMD_SET_DEVICE_PIN && len >= 5) { // get pin from command frame uint32_t pin; memcpy(&pin, &cmd_frame[1], 4); // ensure pin is zero, or a valid 6 digit pin - if (pin == 0 || (pin >= 100000 && pin <= 999999)) - { + if (pin == 0 || (pin >= 100000 && pin <= 999999)) { _prefs.ble_pin = pin; savePrefs(); writeOKFrame(); } - else - { + else { writeErrFrame(ERR_CODE_ILLEGAL_ARG); } } - else if (cmd_frame[0] == CMD_GET_CUSTOM_VARS) - { + else if (cmd_frame[0] == CMD_GET_CUSTOM_VARS) { out_frame[0] = RESP_CODE_CUSTOM_VARS; char *dp = (char *)&out_frame[1]; - for (int i = 0; i < sensors.getNumSettings() && dp - (char *)&out_frame[1] < 140; i++) - { - if (i > 0) - { + for (int i = 0; i < sensors.getNumSettings() && dp - (char *)&out_frame[1] < 140; i++) { + if (i > 0) { *dp++ = ','; } strcpy(dp, sensors.getSettingName(i)); @@ -1721,31 +1610,25 @@ void MyMesh::handleCmdFrame(size_t len) } _serial->writeFrame(out_frame, dp - (char *)out_frame); } - else if (cmd_frame[0] == CMD_SET_CUSTOM_VAR && len >= 4) - { + else if (cmd_frame[0] == CMD_SET_CUSTOM_VAR && len >= 4) { cmd_frame[len] = 0; char *sp = (char *)&cmd_frame[1]; char *np = strchr(sp, ':'); // look for separator char - if (np) - { + if (np) { *np++ = 0; // modify 'cmd_frame', replace ':' with null bool success = sensors.setSettingValue(sp, np); - if (success) - { + if (success) { writeOKFrame(); } - else - { + else { writeErrFrame(ERR_CODE_ILLEGAL_ARG); } } - else - { + else { writeErrFrame(ERR_CODE_ILLEGAL_ARG); } } - else - { + else { writeErrFrame(ERR_CODE_UNSUPPORTED_CMD); MESH_DEBUG_PRINTLN("ERROR: unknown command: %02X", cmd_frame[0]); } @@ -1756,42 +1639,35 @@ void MyMesh::loop() BaseChatMesh::loop(); size_t len = _serial->checkRecvFrame(cmd_frame); - if (len > 0) - { + if (len > 0) { handleCmdFrame(len); } else if (_iter_started // check if our ContactsIterator is 'running' && !_serial->isWriteBusy() // don't spam the Serial Interface too quickly! - ) - { + ) { ContactInfo contact; - if (_iter.hasNext(this, contact)) - { - if (contact.lastmod > _iter_filter_since) - { // apply the 'since' filter + if (_iter.hasNext(this, contact)) { + if (contact.lastmod > _iter_filter_since) { // apply the 'since' filter writeContactRespFrame(RESP_CODE_CONTACT, contact); - if (contact.lastmod > _most_recent_lastmod) - { + if (contact.lastmod > _most_recent_lastmod) { _most_recent_lastmod = contact.lastmod; // save for the RESP_CODE_END_OF_CONTACTS frame } } } - else - { // EOF + else { // EOF out_frame[0] = RESP_CODE_END_OF_CONTACTS; - memcpy(&out_frame[1], &_most_recent_lastmod, 4); // include the most recent lastmod, so app can update their 'since' + memcpy(&out_frame[1], &_most_recent_lastmod, + 4); // include the most recent lastmod, so app can update their 'since' _serial->writeFrame(out_frame, 5); _iter_started = false; } } - else if (!_serial->isWriteBusy()) - { + else if (!_serial->isWriteBusy()) { checkConnections(); } // is there are pending dirty contacts write needed? - if (dirty_contacts_expiry && millisHasNowPassed(dirty_contacts_expiry)) - { + if (dirty_contacts_expiry && millisHasNowPassed(dirty_contacts_expiry)) { saveContacts(); dirty_contacts_expiry = 0; } @@ -1805,14 +1681,12 @@ void MyMesh::loop() bool MyMesh::advert() { auto pkt = createSelfAdvert(_prefs.node_name, sensors.node_lat, sensors.node_lon); - if (pkt) - { + if (pkt) { sendZeroHop(pkt); writeOKFrame(); return true; } - else - { + else { writeErrFrame(ERR_CODE_TABLE_FULL); return false; } diff --git a/examples/companion_radio/MyMesh.h b/examples/companion_radio/MyMesh.h index a4794f1f1..574b9878f 100644 --- a/examples/companion_radio/MyMesh.h +++ b/examples/companion_radio/MyMesh.h @@ -1,21 +1,20 @@ -#ifndef MYMESH_H -#define MYMESH_H +#pragma once #include #include #ifdef DISPLAY_CLASS - #include "UITask.h" +#include "UITask.h" #endif /*------------ Frame Protocol --------------*/ -#define FIRMWARE_VER_CODE 5 +#define FIRMWARE_VER_CODE 5 #ifndef FIRMWARE_BUILD_DATE - #define FIRMWARE_BUILD_DATE "24 May 2025" +#define FIRMWARE_BUILD_DATE "24 May 2025" #endif #ifndef FIRMWARE_VERSION - #define FIRMWARE_VERSION "v1.6.2" +#define FIRMWARE_VERSION "v1.6.2" #endif #if defined(NRF52_PLATFORM) || defined(STM32_PLATFORM) @@ -26,258 +25,197 @@ #include #endif -#include -#include -#include -#include -#include #include "NodePrefs.h" + #include +#include +#include +#include +#include +#include #include /* ---------------------------------- CONFIGURATION ------------------------------------- */ #ifndef LORA_FREQ - #define LORA_FREQ 915.0 +#define LORA_FREQ 915.0 #endif #ifndef LORA_BW - #define LORA_BW 250 +#define LORA_BW 250 #endif #ifndef LORA_SF - #define LORA_SF 10 +#define LORA_SF 10 #endif #ifndef LORA_CR - #define LORA_CR 5 +#define LORA_CR 5 #endif #ifndef LORA_TX_POWER - #define LORA_TX_POWER 20 +#define LORA_TX_POWER 20 #endif #ifndef MAX_LORA_TX_POWER - #define MAX_LORA_TX_POWER LORA_TX_POWER +#define MAX_LORA_TX_POWER LORA_TX_POWER #endif #ifndef MAX_CONTACTS - #define MAX_CONTACTS 100 +#define MAX_CONTACTS 100 #endif #ifndef OFFLINE_QUEUE_SIZE - #define OFFLINE_QUEUE_SIZE 16 +#define OFFLINE_QUEUE_SIZE 16 #endif #ifndef BLE_NAME_PREFIX - #define BLE_NAME_PREFIX "MeshCore-" +#define BLE_NAME_PREFIX "MeshCore-" #endif #include -#define SEND_TIMEOUT_BASE_MILLIS 500 -#define FLOOD_SEND_TIMEOUT_FACTOR 16.0f -#define DIRECT_SEND_PERHOP_FACTOR 6.0f -#define DIRECT_SEND_PERHOP_EXTRA_MILLIS 250 -#define LAZY_CONTACTS_WRITE_DELAY 5000 - -#define PUBLIC_GROUP_PSK "izOH6cXN6mrJ5e26oRXNcg==" - -#define CMD_APP_START 1 -#define CMD_SEND_TXT_MSG 2 -#define CMD_SEND_CHANNEL_TXT_MSG 3 -#define CMD_GET_CONTACTS 4 // with optional 'since' (for efficient sync) -#define CMD_GET_DEVICE_TIME 5 -#define CMD_SET_DEVICE_TIME 6 -#define CMD_SEND_SELF_ADVERT 7 -#define CMD_SET_ADVERT_NAME 8 -#define CMD_ADD_UPDATE_CONTACT 9 -#define CMD_SYNC_NEXT_MESSAGE 10 -#define CMD_SET_RADIO_PARAMS 11 -#define CMD_SET_RADIO_TX_POWER 12 -#define CMD_RESET_PATH 13 -#define CMD_SET_ADVERT_LATLON 14 -#define CMD_REMOVE_CONTACT 15 -#define CMD_SHARE_CONTACT 16 -#define CMD_EXPORT_CONTACT 17 -#define CMD_IMPORT_CONTACT 18 -#define CMD_REBOOT 19 -#define CMD_GET_BATTERY_VOLTAGE 20 -#define CMD_SET_TUNING_PARAMS 21 -#define CMD_DEVICE_QEURY 22 -#define CMD_EXPORT_PRIVATE_KEY 23 -#define CMD_IMPORT_PRIVATE_KEY 24 -#define CMD_SEND_RAW_DATA 25 -#define CMD_SEND_LOGIN 26 -#define CMD_SEND_STATUS_REQ 27 -#define CMD_HAS_CONNECTION 28 -#define CMD_LOGOUT 29 // 'Disconnect' -#define CMD_GET_CONTACT_BY_KEY 30 -#define CMD_GET_CHANNEL 31 -#define CMD_SET_CHANNEL 32 -#define CMD_SIGN_START 33 -#define CMD_SIGN_DATA 34 -#define CMD_SIGN_FINISH 35 -#define CMD_SEND_TRACE_PATH 36 -#define CMD_SET_DEVICE_PIN 37 -#define CMD_SET_OTHER_PARAMS 38 -#define CMD_SEND_TELEMETRY_REQ 39 -#define CMD_GET_CUSTOM_VARS 40 -#define CMD_SET_CUSTOM_VAR 41 - -#define RESP_CODE_OK 0 -#define RESP_CODE_ERR 1 -#define RESP_CODE_CONTACTS_START 2 // first reply to CMD_GET_CONTACTS -#define RESP_CODE_CONTACT 3 // multiple of these (after CMD_GET_CONTACTS) -#define RESP_CODE_END_OF_CONTACTS 4 // last reply to CMD_GET_CONTACTS -#define RESP_CODE_SELF_INFO 5 // reply to CMD_APP_START -#define RESP_CODE_SENT 6 // reply to CMD_SEND_TXT_MSG -#define RESP_CODE_CONTACT_MSG_RECV 7 // a reply to CMD_SYNC_NEXT_MESSAGE (ver < 3) -#define RESP_CODE_CHANNEL_MSG_RECV 8 // a reply to CMD_SYNC_NEXT_MESSAGE (ver < 3) -#define RESP_CODE_CURR_TIME 9 // a reply to CMD_GET_DEVICE_TIME -#define RESP_CODE_NO_MORE_MESSAGES 10 // a reply to CMD_SYNC_NEXT_MESSAGE -#define RESP_CODE_EXPORT_CONTACT 11 -#define RESP_CODE_BATTERY_VOLTAGE 12 // a reply to a CMD_GET_BATTERY_VOLTAGE -#define RESP_CODE_DEVICE_INFO 13 // a reply to CMD_DEVICE_QEURY -#define RESP_CODE_PRIVATE_KEY 14 // a reply to CMD_EXPORT_PRIVATE_KEY -#define RESP_CODE_DISABLED 15 -#define RESP_CODE_CONTACT_MSG_RECV_V3 16 // a reply to CMD_SYNC_NEXT_MESSAGE (ver >= 3) -#define RESP_CODE_CHANNEL_MSG_RECV_V3 17 // a reply to CMD_SYNC_NEXT_MESSAGE (ver >= 3) -#define RESP_CODE_CHANNEL_INFO 18 // a reply to CMD_GET_CHANNEL -#define RESP_CODE_SIGN_START 19 -#define RESP_CODE_SIGNATURE 20 -#define RESP_CODE_CUSTOM_VARS 21 +#define SEND_TIMEOUT_BASE_MILLIS 500 +#define FLOOD_SEND_TIMEOUT_FACTOR 16.0f +#define DIRECT_SEND_PERHOP_FACTOR 6.0f +#define DIRECT_SEND_PERHOP_EXTRA_MILLIS 250 +#define LAZY_CONTACTS_WRITE_DELAY 5000 + +#define PUBLIC_GROUP_PSK "izOH6cXN6mrJ5e26oRXNcg==" // these are _pushed_ to client app at any time -#define PUSH_CODE_ADVERT 0x80 -#define PUSH_CODE_PATH_UPDATED 0x81 -#define PUSH_CODE_SEND_CONFIRMED 0x82 -#define PUSH_CODE_MSG_WAITING 0x83 -#define PUSH_CODE_RAW_DATA 0x84 -#define PUSH_CODE_LOGIN_SUCCESS 0x85 -#define PUSH_CODE_LOGIN_FAIL 0x86 -#define PUSH_CODE_STATUS_RESPONSE 0x87 -#define PUSH_CODE_LOG_RX_DATA 0x88 -#define PUSH_CODE_TRACE_DATA 0x89 -#define PUSH_CODE_NEW_ADVERT 0x8A -#define PUSH_CODE_TELEMETRY_RESPONSE 0x8B - -#define ERR_CODE_UNSUPPORTED_CMD 1 -#define ERR_CODE_NOT_FOUND 2 -#define ERR_CODE_TABLE_FULL 3 -#define ERR_CODE_BAD_STATE 4 -#define ERR_CODE_FILE_IO_ERROR 5 -#define ERR_CODE_ILLEGAL_ARG 6 +#define PUSH_CODE_ADVERT 0x80 +#define PUSH_CODE_PATH_UPDATED 0x81 +#define PUSH_CODE_SEND_CONFIRMED 0x82 +#define PUSH_CODE_MSG_WAITING 0x83 +#define PUSH_CODE_RAW_DATA 0x84 +#define PUSH_CODE_LOGIN_SUCCESS 0x85 +#define PUSH_CODE_LOGIN_FAIL 0x86 +#define PUSH_CODE_STATUS_RESPONSE 0x87 +#define PUSH_CODE_LOG_RX_DATA 0x88 +#define PUSH_CODE_TRACE_DATA 0x89 +#define PUSH_CODE_NEW_ADVERT 0x8A +#define PUSH_CODE_TELEMETRY_RESPONSE 0x8B + +#define ERR_CODE_UNSUPPORTED_CMD 1 +#define ERR_CODE_NOT_FOUND 2 +#define ERR_CODE_TABLE_FULL 3 +#define ERR_CODE_BAD_STATE 4 +#define ERR_CODE_FILE_IO_ERROR 5 +#define ERR_CODE_ILLEGAL_ARG 6 /* -------------------------------------------------------------------------------------- */ -#define REQ_TYPE_GET_STATUS 0x01 // same as _GET_STATS -#define REQ_TYPE_KEEP_ALIVE 0x02 -#define REQ_TYPE_GET_TELEMETRY_DATA 0x03 +#define REQ_TYPE_GET_STATUS 0x01 // same as _GET_STATS +#define REQ_TYPE_KEEP_ALIVE 0x02 +#define REQ_TYPE_GET_TELEMETRY_DATA 0x03 -#define MAX_SIGN_DATA_LEN (8*1024) // 8K +#define MAX_SIGN_DATA_LEN (8 * 1024) // 8K class MyMesh : public BaseChatMesh { public: - MyMesh(mesh::Radio& radio, mesh::RNG& rng, mesh::RTCClock& rtc, SimpleMeshTables& tables); - - void begin(FILESYSTEM& fs, bool has_display); - void startInterface(BaseSerialInterface& serial); - void loadPrefsInt(const char* filename); - void savePrefs(); - - const char* getNodeName(); - NodePrefs* getNodePrefs(); - uint32_t getBLEPin(); - - void loop(); - void handleCmdFrame(size_t len); - bool advert(); + MyMesh(mesh::Radio &radio, mesh::RNG &rng, mesh::RTCClock &rtc, SimpleMeshTables &tables); + + void begin(FILESYSTEM &fs, bool has_display); + void startInterface(BaseSerialInterface &serial); + void loadPrefsInt(const char *filename); + void savePrefs(); + + const char *getNodeName(); + NodePrefs *getNodePrefs(); + uint32_t getBLEPin(); + + void loop(); + void handleCmdFrame(size_t len); + bool advert(); protected: - float getAirtimeBudgetFactor() const override; - int getInterferenceThreshold() const override; - int calcRxDelay(float score, uint32_t air_time) const override; - - void logRxRaw(float snr, float rssi, const uint8_t raw[], int len) override; - bool isAutoAddEnabled() const override; - void onDiscoveredContact(ContactInfo& contact, bool is_new) override; - void onContactPathUpdated(const ContactInfo& contact) override; - bool processAck(const uint8_t *data) override; - void queueMessage(const ContactInfo& from, uint8_t txt_type, mesh::Packet* pkt, - uint32_t sender_timestamp, const uint8_t* extra, int extra_len, const char *text); - - void onMessageRecv(const ContactInfo& from, mesh::Packet* pkt, uint32_t sender_timestamp, const char *text) override; - void onCommandDataRecv(const ContactInfo& from, mesh::Packet* pkt, uint32_t sender_timestamp, const char *text) override; - void onSignedMessageRecv(const ContactInfo& from, mesh::Packet* pkt, uint32_t sender_timestamp, - const uint8_t *sender_prefix, const char *text) override; - void onChannelMessageRecv(const mesh::GroupChannel& channel, mesh::Packet* pkt, uint32_t timestamp, const char *text) override; - - uint8_t onContactRequest(const ContactInfo& contact, uint32_t sender_timestamp, const uint8_t* data, uint8_t len, uint8_t* reply) override; - void onContactResponse(const ContactInfo& contact, const uint8_t* data, uint8_t len) override; - void onRawDataRecv(mesh::Packet* packet) override; - void onTraceRecv(mesh::Packet* packet, uint32_t tag, uint32_t auth_code, uint8_t flags, const uint8_t* path_snrs, - const uint8_t* path_hashes, uint8_t path_len) override; - - uint32_t calcFloodTimeoutMillisFor(uint32_t pkt_airtime_millis) const override; - uint32_t calcDirectTimeoutMillisFor(uint32_t pkt_airtime_millis, uint8_t path_len) const override; - void onSendTimeout() override; + float getAirtimeBudgetFactor() const override; + int getInterferenceThreshold() const override; + int calcRxDelay(float score, uint32_t air_time) const override; + + void logRxRaw(float snr, float rssi, const uint8_t raw[], int len) override; + bool isAutoAddEnabled() const override; + void onDiscoveredContact(ContactInfo &contact, bool is_new) override; + void onContactPathUpdated(const ContactInfo &contact) override; + bool processAck(const uint8_t *data) override; + void queueMessage(const ContactInfo &from, uint8_t txt_type, mesh::Packet *pkt, uint32_t sender_timestamp, + const uint8_t *extra, int extra_len, const char *text); + + void onMessageRecv(const ContactInfo &from, mesh::Packet *pkt, uint32_t sender_timestamp, + const char *text) override; + void onCommandDataRecv(const ContactInfo &from, mesh::Packet *pkt, uint32_t sender_timestamp, + const char *text) override; + void onSignedMessageRecv(const ContactInfo &from, mesh::Packet *pkt, uint32_t sender_timestamp, + const uint8_t *sender_prefix, const char *text) override; + void onChannelMessageRecv(const mesh::GroupChannel &channel, mesh::Packet *pkt, uint32_t timestamp, + const char *text) override; + + uint8_t onContactRequest(const ContactInfo &contact, uint32_t sender_timestamp, const uint8_t *data, + uint8_t len, uint8_t *reply) override; + void onContactResponse(const ContactInfo &contact, const uint8_t *data, uint8_t len) override; + void onRawDataRecv(mesh::Packet *packet) override; + void onTraceRecv(mesh::Packet *packet, uint32_t tag, uint32_t auth_code, uint8_t flags, + const uint8_t *path_snrs, const uint8_t *path_hashes, uint8_t path_len) override; + + uint32_t calcFloodTimeoutMillisFor(uint32_t pkt_airtime_millis) const override; + uint32_t calcDirectTimeoutMillisFor(uint32_t pkt_airtime_millis, uint8_t path_len) const override; + void onSendTimeout() override; private: - void writeOKFrame(); - void writeErrFrame(uint8_t err_code); - void writeDisabledFrame(); - void writeContactRespFrame(uint8_t code, const ContactInfo& contact); - void updateContactFromFrame(ContactInfo& contact, const uint8_t* frame, int len); - void addToOfflineQueue(const uint8_t frame[], int len); - int getFromOfflineQueue(uint8_t frame[]); - void loadMainIdentity(); - bool saveMainIdentity(const mesh::LocalIdentity& identity); - void loadContacts(); - void saveContacts(); - void loadChannels(); - void saveChannels(); - int getBlobByKey(const uint8_t key[], int key_len, uint8_t dest_buf[]) override; - bool putBlobByKey(const uint8_t key[], int key_len, const uint8_t src_buf[], int len) override; + void writeOKFrame(); + void writeErrFrame(uint8_t err_code); + void writeDisabledFrame(); + void writeContactRespFrame(uint8_t code, const ContactInfo &contact); + void updateContactFromFrame(ContactInfo &contact, const uint8_t *frame, int len); + void addToOfflineQueue(const uint8_t frame[], int len); + int getFromOfflineQueue(uint8_t frame[]); + void loadMainIdentity(); + bool saveMainIdentity(const mesh::LocalIdentity &identity); + void loadContacts(); + void saveContacts(); + void loadChannels(); + void saveChannels(); + int getBlobByKey(const uint8_t key[], int key_len, uint8_t dest_buf[]) override; + bool putBlobByKey(const uint8_t key[], int key_len, const uint8_t src_buf[], int len) override; private: - FILESYSTEM* _fs; - IdentityStore* _identity_store; - NodePrefs _prefs; - uint32_t pending_login; - uint32_t pending_status; - uint32_t pending_telemetry; - BaseSerialInterface* _serial; - - ContactsIterator _iter; - uint32_t _iter_filter_since; - uint32_t _most_recent_lastmod; - uint32_t _active_ble_pin; - bool _iter_started; - uint8_t app_target_ver; - uint8_t* sign_data; - uint32_t sign_data_len; - unsigned long dirty_contacts_expiry; - - uint8_t cmd_frame[MAX_FRAME_SIZE + 1]; - uint8_t out_frame[MAX_FRAME_SIZE + 1]; - CayenneLPP telemetry; - - struct Frame { - uint8_t len; - uint8_t buf[MAX_FRAME_SIZE]; - }; - int offline_queue_len; - Frame offline_queue[OFFLINE_QUEUE_SIZE]; - - struct AckTableEntry { - unsigned long msg_sent; - uint32_t ack; - }; - #define EXPECTED_ACK_TABLE_SIZE 8 - AckTableEntry expected_ack_table[EXPECTED_ACK_TABLE_SIZE]; // circular table - int next_ack_idx; + FILESYSTEM *_fs; + IdentityStore *_identity_store; + NodePrefs _prefs; + uint32_t pending_login; + uint32_t pending_status; + uint32_t pending_telemetry; + BaseSerialInterface *_serial; + + ContactsIterator _iter; + uint32_t _iter_filter_since; + uint32_t _most_recent_lastmod; + uint32_t _active_ble_pin; + bool _iter_started; + uint8_t app_target_ver; + uint8_t *sign_data; + uint32_t sign_data_len; + unsigned long dirty_contacts_expiry; + + uint8_t cmd_frame[MAX_FRAME_SIZE + 1]; + uint8_t out_frame[MAX_FRAME_SIZE + 1]; + CayenneLPP telemetry; + + struct Frame { + uint8_t len; + uint8_t buf[MAX_FRAME_SIZE]; + }; + int offline_queue_len; + Frame offline_queue[OFFLINE_QUEUE_SIZE]; + + struct AckTableEntry { + unsigned long msg_sent; + uint32_t ack; + }; +#define EXPECTED_ACK_TABLE_SIZE 8 + AckTableEntry expected_ack_table[EXPECTED_ACK_TABLE_SIZE]; // circular table + int next_ack_idx; }; extern StdRNG fast_rng; extern SimpleMeshTables tables; extern MyMesh the_mesh; #ifdef DISPLAY_CLASS - extern UITask ui_task; -#endif -#endif // MYMESH_H \ No newline at end of file +extern UITask ui_task; +#endif \ No newline at end of file diff --git a/examples/companion_radio/NodePrefs.h b/examples/companion_radio/NodePrefs.h index 09d04266b..44d7ecbf2 100644 --- a/examples/companion_radio/NodePrefs.h +++ b/examples/companion_radio/NodePrefs.h @@ -1,13 +1,11 @@ -#ifndef NODE_PREFS_H -#define NODE_PREFS_H - +#pragma once #include // For uint8_t, uint32_t -#define TELEM_MODE_DENY 0 -#define TELEM_MODE_ALLOW_FLAGS 1 // use contact.flags -#define TELEM_MODE_ALLOW_ALL 2 +#define TELEM_MODE_DENY 0 +#define TELEM_MODE_ALLOW_FLAGS 1 // use contact.flags +#define TELEM_MODE_ALLOW_ALL 2 -struct NodePrefs { // persisted to file +struct NodePrefs { // persisted to file float airtime_factor; char node_name[32]; float freq; @@ -22,6 +20,4 @@ struct NodePrefs { // persisted to file uint8_t telemetry_mode_env; float rx_delay_base; uint32_t ble_pin; -}; - -#endif // NODE_PREFS_H \ No newline at end of file +}; \ No newline at end of file diff --git a/examples/companion_radio/UITask.h b/examples/companion_radio/UITask.h index 6d7e1eb34..f52c0961c 100644 --- a/examples/companion_radio/UITask.h +++ b/examples/companion_radio/UITask.h @@ -1,53 +1,43 @@ -#ifndef UI_TASK_H -#define UI_TASK_H - +#pragma once #include #include #include #ifdef PIN_BUZZER - #include +#include #endif -#include "NodePrefs.h" #include "Button.h" +#include "NodePrefs.h" - enum class UIEventType -{ - none, - contactMessage, - channelMessage, - roomMessage, - newContactMessage, - ack -}; +enum class UIEventType { none, contactMessage, channelMessage, roomMessage, newContactMessage, ack }; class UITask { - DisplayDriver* _display; - mesh::MainBoard* _board; + DisplayDriver *_display; + mesh::MainBoard *_board; #ifdef PIN_BUZZER genericBuzzer buzzer; #endif unsigned long _next_refresh, _auto_off; bool _connected; uint32_t _pin_code; - NodePrefs* _node_prefs; + NodePrefs *_node_prefs; char _version_info[32]; char _origin[62]; char _msg[80]; int _msgcount; bool _need_refresh = true; - bool _displayWasOn = false; // Track display state before button press + bool _displayWasOn = false; // Track display state before button press // Button handlers #if defined(PIN_USER_BTN) || defined(PIN_USER_BTN_ANA) - Button* _userButton = nullptr; + Button *_userButton = nullptr; #endif void renderCurrScreen(); void userLedHandler(); void renderBatteryIndicator(uint16_t batteryMilliVolts); - + // Button action handlers void handleButtonAnyPress(); void handleButtonShortPress(); @@ -55,22 +45,21 @@ class UITask { void handleButtonTriplePress(); void handleButtonLongPress(); - public: - - UITask(mesh::MainBoard* board) : _board(board), _display(NULL) { - _next_refresh = 0; - _connected = false; + UITask(mesh::MainBoard *board) : _board(board), _display(NULL) + { + _next_refresh = 0; + _connected = false; } - void begin(DisplayDriver* display, NodePrefs* node_prefs, const char* build_date, const char* firmware_version, uint32_t pin_code); + void begin(DisplayDriver *display, NodePrefs *node_prefs, const char *build_date, + const char *firmware_version, uint32_t pin_code); void setHasConnection(bool connected) { _connected = connected; } bool hasDisplay() const { return _display != NULL; } void clearMsgPreview(); void msgRead(int msgcount); - void newMsg(uint8_t path_len, const char* from_name, const char* text, int msgcount); + void newMsg(uint8_t path_len, const char *from_name, const char *text, int msgcount); void soundBuzzer(UIEventType bet = UIEventType::none); void shutdown(bool restart = false); void loop(); -}; -#endif //UI_TASK_H \ No newline at end of file +}; \ No newline at end of file diff --git a/examples/simple_secure_chat/main.cpp b/examples/simple_secure_chat/main.cpp index 63ff20da3..2440b6976 100644 --- a/examples/simple_secure_chat/main.cpp +++ b/examples/simple_secure_chat/main.cpp @@ -1,56 +1,57 @@ -#include // needed for PlatformIO +#include // needed for PlatformIO #include #if defined(NRF52_PLATFORM) - #include +#include #elif defined(RP2040_PLATFORM) - #include +#include #elif defined(ESP32) - #include +#include #endif +#include #include -#include -#include #include -#include +#include +#include #include /* ---------------------------------- CONFIGURATION ------------------------------------- */ -#define FIRMWARE_VER_TEXT "v2 (build: 4 Feb 2025)" +#define FIRMWARE_VER_TEXT "v2 (build: 4 Feb 2025)" #ifndef LORA_FREQ - #define LORA_FREQ 915.0 +#define LORA_FREQ 915.0 #endif #ifndef LORA_BW - #define LORA_BW 250 +#define LORA_BW 250 #endif #ifndef LORA_SF - #define LORA_SF 10 +#define LORA_SF 10 #endif #ifndef LORA_CR - #define LORA_CR 5 +#define LORA_CR 5 #endif #ifndef LORA_TX_POWER - #define LORA_TX_POWER 20 +#define LORA_TX_POWER 20 #endif #ifndef MAX_CONTACTS - #define MAX_CONTACTS 100 +#define MAX_CONTACTS 100 #endif #include -#define SEND_TIMEOUT_BASE_MILLIS 500 -#define FLOOD_SEND_TIMEOUT_FACTOR 16.0f -#define DIRECT_SEND_PERHOP_FACTOR 6.0f -#define DIRECT_SEND_PERHOP_EXTRA_MILLIS 250 +#define SEND_TIMEOUT_BASE_MILLIS 500 +#define FLOOD_SEND_TIMEOUT_FACTOR 16.0f +#define DIRECT_SEND_PERHOP_FACTOR 6.0f +#define DIRECT_SEND_PERHOP_EXTRA_MILLIS 250 -#define PUBLIC_GROUP_PSK "izOH6cXN6mrJ5e26oRXNcg==" +#define PUBLIC_GROUP_PSK "izOH6cXN6mrJ5e26oRXNcg==" // Believe it or not, this std C function is busted on some platforms! -static uint32_t _atoi(const char* sp) { +static uint32_t _atoi(const char *sp) +{ uint32_t n = 0; while (*sp && *sp >= '0' && *sp <= '9') { n *= 10; @@ -61,7 +62,7 @@ static uint32_t _atoi(const char* sp) { /* -------------------------------------------------------------------------------------- */ -struct NodePrefs { // persisted to file +struct NodePrefs { // persisted to file float airtime_factor; char node_name[32]; double node_lat, node_lon; @@ -71,30 +72,35 @@ struct NodePrefs { // persisted to file }; class MyMesh : public BaseChatMesh, ContactVisitor { - FILESYSTEM* _fs; + FILESYSTEM *_fs; NodePrefs _prefs; uint32_t expected_ack_crc; - ChannelDetails* _public; + ChannelDetails *_public; unsigned long last_msg_sent; - ContactInfo* curr_recipient; - char command[512+10]; + ContactInfo *curr_recipient; + char command[512 + 10]; uint8_t tmp_buf[256]; char hex_buf[512]; - const char* getTypeName(uint8_t type) const { - if (type == ADV_TYPE_CHAT) return "Chat"; - if (type == ADV_TYPE_REPEATER) return "Repeater"; - if (type == ADV_TYPE_ROOM) return "Room"; - return "??"; // unknown + const char *getTypeName(uint8_t type) const + { + if (type == ADV_TYPE_CHAT) + return "Chat"; + if (type == ADV_TYPE_REPEATER) + return "Repeater"; + if (type == ADV_TYPE_ROOM) + return "Room"; + return "??"; // unknown } - void loadContacts() { + void loadContacts() + { if (_fs->exists("/contacts")) { - #if defined(RP2040_PLATFORM) +#if defined(RP2040_PLATFORM) File file = _fs->open("/contacts", "r"); - #else +#else File file = _fs->open("/contacts"); - #endif +#endif if (file) { bool full = false; while (!full) { @@ -104,28 +110,31 @@ class MyMesh : public BaseChatMesh, ContactVisitor { uint32_t reserved; bool success = (file.read(pub_key, 32) == 32); - success = success && (file.read((uint8_t *) &c.name, 32) == 32); + success = success && (file.read((uint8_t *)&c.name, 32) == 32); success = success && (file.read(&c.type, 1) == 1); success = success && (file.read(&c.flags, 1) == 1); success = success && (file.read(&unused, 1) == 1); - success = success && (file.read((uint8_t *) &reserved, 4) == 4); - success = success && (file.read((uint8_t *) &c.out_path_len, 1) == 1); - success = success && (file.read((uint8_t *) &c.last_advert_timestamp, 4) == 4); + success = success && (file.read((uint8_t *)&reserved, 4) == 4); + success = success && (file.read((uint8_t *)&c.out_path_len, 1) == 1); + success = success && (file.read((uint8_t *)&c.last_advert_timestamp, 4) == 4); success = success && (file.read(c.out_path, 64) == 64); - c.gps_lat = c.gps_lon = 0; // not yet supported + c.gps_lat = c.gps_lon = 0; // not yet supported - if (!success) break; // EOF + if (!success) + break; // EOF c.id = mesh::Identity(pub_key); c.lastmod = 0; - if (!addContact(c)) full = true; + if (!addContact(c)) + full = true; } file.close(); } } } - void saveContacts() { + void saveContacts() + { #if defined(NRF52_PLATFORM) _fs->remove("/contacts"); File file = _fs->open("/contacts", FILE_O_WRITE); @@ -142,44 +151,50 @@ class MyMesh : public BaseChatMesh, ContactVisitor { while (iter.hasNext(this, c)) { bool success = (file.write(c.id.pub_key, 32) == 32); - success = success && (file.write((uint8_t *) &c.name, 32) == 32); + success = success && (file.write((uint8_t *)&c.name, 32) == 32); success = success && (file.write(&c.type, 1) == 1); success = success && (file.write(&c.flags, 1) == 1); success = success && (file.write(&unused, 1) == 1); - success = success && (file.write((uint8_t *) &reserved, 4) == 4); - success = success && (file.write((uint8_t *) &c.out_path_len, 1) == 1); - success = success && (file.write((uint8_t *) &c.last_advert_timestamp, 4) == 4); + success = success && (file.write((uint8_t *)&reserved, 4) == 4); + success = success && (file.write((uint8_t *)&c.out_path_len, 1) == 1); + success = success && (file.write((uint8_t *)&c.last_advert_timestamp, 4) == 4); success = success && (file.write(c.out_path, 64) == 64); - if (!success) break; // write failed + if (!success) + break; // write failed } file.close(); } } - void setClock(uint32_t timestamp) { + void setClock(uint32_t timestamp) + { uint32_t curr = getRTCClock()->getCurrentTime(); if (timestamp > curr) { getRTCClock()->setCurrentTime(timestamp); Serial.println(" (OK - clock set!)"); - } else { + } + else { Serial.println(" (ERR: clock cannot go backwards)"); } } - void importCard(const char* command) { - while (*command == ' ') command++; // skip leading spaces + void importCard(const char *command) + { + while (*command == ' ') + command++; // skip leading spaces if (memcmp(command, "meshcore://", 11) == 0) { - command += 11; // skip the prefix - char *ep = strchr(command, 0); // find end of string + command += 11; // skip the prefix + char *ep = strchr(command, 0); // find end of string while (ep > command) { ep--; - if (mesh::Utils::isHexChar(*ep)) break; // found tail end of card - *ep = 0; // remove trailing spaces and other junk + if (mesh::Utils::isHexChar(*ep)) + break; // found tail end of card + *ep = 0; // remove trailing spaces and other junk } int len = strlen(command); if (len % 2 == 0) { - len >>= 1; // halve, for num bytes + len >>= 1; // halve, for num bytes if (mesh::Utils::fromHex(tmp_buf, len, command)) { importContact(tmp_buf, len); return; @@ -190,97 +205,112 @@ class MyMesh : public BaseChatMesh, ContactVisitor { } protected: - float getAirtimeBudgetFactor() const override { - return _prefs.airtime_factor; - } + float getAirtimeBudgetFactor() const override { return _prefs.airtime_factor; } - int calcRxDelay(float score, uint32_t air_time) const override { - return 0; // disable rxdelay + int calcRxDelay(float score, uint32_t air_time) const override + { + return 0; // disable rxdelay } - bool allowPacketForward(const mesh::Packet* packet) override { - return true; - } + bool allowPacketForward(const mesh::Packet *packet) override { return true; } - void onDiscoveredContact(ContactInfo& contact, bool is_new) override { + void onDiscoveredContact(ContactInfo &contact, bool is_new) override + { // TODO: if not in favs, prompt to add as fav(?) Serial.printf("ADVERT from -> %s\n", contact.name); Serial.printf(" type: %s\n", getTypeName(contact.type)); - Serial.print(" public key: "); mesh::Utils::printHex(Serial, contact.id.pub_key, PUB_KEY_SIZE); Serial.println(); + Serial.print(" public key: "); + mesh::Utils::printHex(Serial, contact.id.pub_key, PUB_KEY_SIZE); + Serial.println(); saveContacts(); } - void onContactPathUpdated(const ContactInfo& contact) override { - Serial.printf("PATH to: %s, path_len=%d\n", contact.name, (int32_t) contact.out_path_len); + void onContactPathUpdated(const ContactInfo &contact) override + { + Serial.printf("PATH to: %s, path_len=%d\n", contact.name, (int32_t)contact.out_path_len); saveContacts(); } - bool processAck(const uint8_t *data) override { - if (memcmp(data, &expected_ack_crc, 4) == 0) { // got an ACK from recipient + bool processAck(const uint8_t *data) override + { + if (memcmp(data, &expected_ack_crc, 4) == 0) { // got an ACK from recipient Serial.printf(" Got ACK! (round trip: %d millis)\n", _ms->getMillis() - last_msg_sent); // NOTE: the same ACK can be received multiple times! - expected_ack_crc = 0; // reset our expected hash, now that we have received ACK + expected_ack_crc = 0; // reset our expected hash, now that we have received ACK return true; } - //uint32_t crc; - //memcpy(&crc, data, 4); - //MESH_DEBUG_PRINTLN("unknown ACK received: %08X (expected: %08X)", crc, expected_ack_crc); + // uint32_t crc; + // memcpy(&crc, data, 4); + // MESH_DEBUG_PRINTLN("unknown ACK received: %08X (expected: %08X)", crc, expected_ack_crc); return false; } - void onMessageRecv(const ContactInfo& from, mesh::Packet* pkt, uint32_t sender_timestamp, const char *text) override { + void onMessageRecv(const ContactInfo &from, mesh::Packet *pkt, uint32_t sender_timestamp, + const char *text) override + { Serial.printf("(%s) MSG -> from %s\n", pkt->isRouteDirect() ? "DIRECT" : "FLOOD", from.name); Serial.printf(" %s\n", text); - if (strcmp(text, "clock sync") == 0) { // special text command + if (strcmp(text, "clock sync") == 0) { // special text command setClock(sender_timestamp + 1); } } - void onCommandDataRecv(const ContactInfo& from, mesh::Packet* pkt, uint32_t sender_timestamp, const char *text) override { + void onCommandDataRecv(const ContactInfo &from, mesh::Packet *pkt, uint32_t sender_timestamp, + const char *text) override + { } - void onSignedMessageRecv(const ContactInfo& from, mesh::Packet* pkt, uint32_t sender_timestamp, const uint8_t *sender_prefix, const char *text) override { + void onSignedMessageRecv(const ContactInfo &from, mesh::Packet *pkt, uint32_t sender_timestamp, + const uint8_t *sender_prefix, const char *text) override + { } - void onChannelMessageRecv(const mesh::GroupChannel& channel, mesh::Packet* pkt, uint32_t timestamp, const char *text) override { + void onChannelMessageRecv(const mesh::GroupChannel &channel, mesh::Packet *pkt, uint32_t timestamp, + const char *text) override + { if (pkt->isRouteDirect()) { Serial.printf("PUBLIC CHANNEL MSG -> (Direct!)\n"); - } else { + } + else { Serial.printf("PUBLIC CHANNEL MSG -> (Flood) hops %d\n", pkt->path_len); } Serial.printf(" %s\n", text); } - uint8_t onContactRequest(const ContactInfo& contact, uint32_t sender_timestamp, const uint8_t* data, uint8_t len, uint8_t* reply) override { - return 0; // unknown + uint8_t onContactRequest(const ContactInfo &contact, uint32_t sender_timestamp, const uint8_t *data, + uint8_t len, uint8_t *reply) override + { + return 0; // unknown } - void onContactResponse(const ContactInfo& contact, const uint8_t* data, uint8_t len) override { + void onContactResponse(const ContactInfo &contact, const uint8_t *data, uint8_t len) override + { // not supported } - uint32_t calcFloodTimeoutMillisFor(uint32_t pkt_airtime_millis) const override { + uint32_t calcFloodTimeoutMillisFor(uint32_t pkt_airtime_millis) const override + { return SEND_TIMEOUT_BASE_MILLIS + (FLOOD_SEND_TIMEOUT_FACTOR * pkt_airtime_millis); } - uint32_t calcDirectTimeoutMillisFor(uint32_t pkt_airtime_millis, uint8_t path_len) const override { - return SEND_TIMEOUT_BASE_MILLIS + - ( (pkt_airtime_millis*DIRECT_SEND_PERHOP_FACTOR + DIRECT_SEND_PERHOP_EXTRA_MILLIS) * (path_len + 1)); + uint32_t calcDirectTimeoutMillisFor(uint32_t pkt_airtime_millis, uint8_t path_len) const override + { + return SEND_TIMEOUT_BASE_MILLIS + + ((pkt_airtime_millis * DIRECT_SEND_PERHOP_FACTOR + DIRECT_SEND_PERHOP_EXTRA_MILLIS) * + (path_len + 1)); } - void onSendTimeout() override { - Serial.println(" ERROR: timed out, no ACK."); - } + void onSendTimeout() override { Serial.println(" ERROR: timed out, no ACK."); } public: - MyMesh(mesh::Radio& radio, StdRNG& rng, mesh::RTCClock& rtc, SimpleMeshTables& tables) - : BaseChatMesh(radio, *new ArduinoMillis(), rng, rtc, *new StaticPoolPacketManager(16), tables) + MyMesh(mesh::Radio &radio, StdRNG &rng, mesh::RTCClock &rtc, SimpleMeshTables &tables) + : BaseChatMesh(radio, *new ArduinoMillis(), rng, rtc, *new StaticPoolPacketManager(16), tables) { // defaults memset(&_prefs, 0, sizeof(_prefs)); - _prefs.airtime_factor = 2.0; // one third + _prefs.airtime_factor = 2.0; // one third strcpy(_prefs.node_name, "NONAME"); _prefs.freq = LORA_FREQ; _prefs.tx_power_dbm = LORA_TX_POWER; @@ -292,45 +322,49 @@ class MyMesh : public BaseChatMesh, ContactVisitor { float getFreqPref() const { return _prefs.freq; } uint8_t getTxPowerPref() const { return _prefs.tx_power_dbm; } - void begin(FILESYSTEM& fs) { + void begin(FILESYSTEM &fs) + { _fs = &fs; BaseChatMesh::begin(); - #if defined(NRF52_PLATFORM) +#if defined(NRF52_PLATFORM) IdentityStore store(fs, ""); - #elif defined(RP2040_PLATFORM) +#elif defined(RP2040_PLATFORM) IdentityStore store(fs, "/identity"); store.begin(); - #else +#else IdentityStore store(fs, "/identity"); - #endif - if (!store.load("_main", self_id, _prefs.node_name, sizeof(_prefs.node_name))) { // legacy: node_name was from identity file +#endif + if (!store.load("_main", self_id, _prefs.node_name, + sizeof(_prefs.node_name))) { // legacy: node_name was from identity file // Need way to get some entropy to seed RNG Serial.println("Press ENTER to generate key:"); char c = 0; - while (c != '\n') { // wait for ENTER to be pressed - if (Serial.available()) c = Serial.read(); + while (c != '\n') { // wait for ENTER to be pressed + if (Serial.available()) + c = Serial.read(); } ((StdRNG *)getRNG())->begin(millis()); - self_id = mesh::LocalIdentity(getRNG()); // create new random identity + self_id = mesh::LocalIdentity(getRNG()); // create new random identity int count = 0; - while (count < 10 && (self_id.pub_key[0] == 0x00 || self_id.pub_key[0] == 0xFF)) { // reserved id hashes - self_id = mesh::LocalIdentity(getRNG()); count++; + while (count < 10 && (self_id.pub_key[0] == 0x00 || self_id.pub_key[0] == 0xFF)) { // reserved id hashes + self_id = mesh::LocalIdentity(getRNG()); + count++; } store.save("_main", self_id); } // load persisted prefs if (_fs->exists("/node_prefs")) { - #if defined(RP2040_PLATFORM) +#if defined(RP2040_PLATFORM) File file = _fs->open("/node_prefs", "r"); - #else +#else File file = _fs->open("/node_prefs"); - #endif +#endif if (file) { - file.read((uint8_t *) &_prefs, sizeof(_prefs)); + file.read((uint8_t *)&_prefs, sizeof(_prefs)); file.close(); } } @@ -339,7 +373,8 @@ class MyMesh : public BaseChatMesh, ContactVisitor { _public = addChannel("Public", PUBLIC_GROUP_PSK); // pre-configure Andy's public channel } - void savePrefs() { + void savePrefs() + { #if defined(NRF52_PLATFORM) _fs->remove("/node_prefs"); File file = _fs->open("/node_prefs", FILE_O_WRITE); @@ -354,7 +389,8 @@ class MyMesh : public BaseChatMesh, ContactVisitor { } } - void showWelcome() { + void showWelcome() + { Serial.println("===== MeshCore Chat Terminal ====="); Serial.println(); Serial.printf("WELCOME %s\n", _prefs.node_name); @@ -364,7 +400,8 @@ class MyMesh : public BaseChatMesh, ContactVisitor { Serial.println(); } - void sendSelfAdvert(int delay_millis) { + void sendSelfAdvert(int delay_millis) + { auto pkt = createSelfAdvert(_prefs.node_name, _prefs.node_lat, _prefs.node_lon); if (pkt) { sendFlood(pkt, delay_millis); @@ -372,7 +409,8 @@ class MyMesh : public BaseChatMesh, ContactVisitor { } // ContactVisitor - void onContactVisit(const ContactInfo& contact) override { + void onContactVisit(const ContactInfo &contact) override + { Serial.printf(" %s - ", contact.name); char tmp[40]; int32_t secs = contact.last_advert_timestamp - getRTCClock()->getCurrentTime(); @@ -380,129 +418,159 @@ class MyMesh : public BaseChatMesh, ContactVisitor { Serial.println(tmp); } - void handleCommand(const char* command) { - while (*command == ' ') command++; // skip leading spaces + void handleCommand(const char *command) + { + while (*command == ' ') + command++; // skip leading spaces if (memcmp(command, "send ", 5) == 0) { if (curr_recipient) { const char *text = &command[5]; uint32_t est_timeout; - int result = sendMessage(*curr_recipient, getRTCClock()->getCurrentTime(), 0, text, expected_ack_crc, est_timeout); + int result = sendMessage(*curr_recipient, getRTCClock()->getCurrentTime(), 0, text, expected_ack_crc, + est_timeout); if (result == MSG_SEND_FAILED) { Serial.println(" ERROR: unable to send."); - } else { + } + else { last_msg_sent = _ms->getMillis(); Serial.printf(" (message sent - %s)\n", result == MSG_SEND_SENT_FLOOD ? "FLOOD" : "DIRECT"); } - } else { + } + else { Serial.println(" ERROR: no recipient selected (use 'to' cmd)."); } - } else if (memcmp(command, "public ", 7) == 0) { // send GroupChannel msg - uint8_t temp[5+MAX_TEXT_LEN+32]; + } + else if (memcmp(command, "public ", 7) == 0) { // send GroupChannel msg + uint8_t temp[5 + MAX_TEXT_LEN + 32]; uint32_t timestamp = getRTCClock()->getCurrentTime(); - memcpy(temp, ×tamp, 4); // mostly an extra blob to help make packet_hash unique - temp[4] = 0; // attempt and flags + memcpy(temp, ×tamp, 4); // mostly an extra blob to help make packet_hash unique + temp[4] = 0; // attempt and flags - sprintf((char *) &temp[5], "%s: %s", _prefs.node_name, &command[7]); // : - temp[5 + MAX_TEXT_LEN] = 0; // truncate if too long + sprintf((char *)&temp[5], "%s: %s", _prefs.node_name, &command[7]); // : + temp[5 + MAX_TEXT_LEN] = 0; // truncate if too long - int len = strlen((char *) &temp[5]); + int len = strlen((char *)&temp[5]); auto pkt = createGroupDatagram(PAYLOAD_TYPE_GRP_TXT, _public->channel, temp, 5 + len); if (pkt) { sendFlood(pkt); Serial.println(" Sent."); - } else { + } + else { Serial.println(" ERROR: unable to send"); } - } else if (memcmp(command, "list", 4) == 0) { // show Contact list, by most recent + } + else if (memcmp(command, "list", 4) == 0) { // show Contact list, by most recent int n = 0; - if (command[4] == ' ') { // optional param, last 'N' + if (command[4] == ' ') { // optional param, last 'N' n = atoi(&command[5]); } scanRecentContacts(n, this); - } else if (strcmp(command, "clock") == 0) { // show current time + } + else if (strcmp(command, "clock") == 0) { // show current time uint32_t now = getRTCClock()->getCurrentTime(); DateTime dt = DateTime(now); - Serial.printf( "%02d:%02d - %d/%d/%d UTC\n", dt.hour(), dt.minute(), dt.day(), dt.month(), dt.year()); - } else if (memcmp(command, "time ", 5) == 0) { // set time (to epoch seconds) + Serial.printf("%02d:%02d - %d/%d/%d UTC\n", dt.hour(), dt.minute(), dt.day(), dt.month(), dt.year()); + } + else if (memcmp(command, "time ", 5) == 0) { // set time (to epoch seconds) uint32_t secs = _atoi(&command[5]); setClock(secs); - } else if (memcmp(command, "to ", 3) == 0) { // set current recipient + } + else if (memcmp(command, "to ", 3) == 0) { // set current recipient curr_recipient = searchContactsByPrefix(&command[3]); if (curr_recipient) { Serial.printf(" Recipient %s now selected.\n", curr_recipient->name); - } else { + } + else { Serial.println(" Error: Name prefix not found."); } - } else if (strcmp(command, "to") == 0) { // show current recipient + } + else if (strcmp(command, "to") == 0) { // show current recipient if (curr_recipient) { - Serial.printf(" Current: %s\n", curr_recipient->name); - } else { - Serial.println(" Err: no recipient selected"); + Serial.printf(" Current: %s\n", curr_recipient->name); + } + else { + Serial.println(" Err: no recipient selected"); } - } else if (strcmp(command, "advert") == 0) { + } + else if (strcmp(command, "advert") == 0) { auto pkt = createSelfAdvert(_prefs.node_name, _prefs.node_lat, _prefs.node_lon); if (pkt) { sendZeroHop(pkt); Serial.println(" (advert sent, zero hop)."); - } else { + } + else { Serial.println(" ERR: unable to send"); } - } else if (strcmp(command, "reset path") == 0) { + } + else if (strcmp(command, "reset path") == 0) { if (curr_recipient) { resetPathTo(*curr_recipient); saveContacts(); Serial.println(" Done."); } - } else if (memcmp(command, "card", 4) == 0) { + } + else if (memcmp(command, "card", 4) == 0) { Serial.printf("Hello %s\n", _prefs.node_name); auto pkt = createSelfAdvert(_prefs.node_name, _prefs.node_lat, _prefs.node_lon); if (pkt) { - uint8_t len = pkt->writeTo(tmp_buf); - releasePacket(pkt); // undo the obtainNewPacket() + uint8_t len = pkt->writeTo(tmp_buf); + releasePacket(pkt); // undo the obtainNewPacket() mesh::Utils::toHex(hex_buf, tmp_buf, len); Serial.println("Your MeshCore biz card:"); - Serial.print("meshcore://"); Serial.println(hex_buf); + Serial.print("meshcore://"); + Serial.println(hex_buf); Serial.println(); - } else { + } + else { Serial.println(" Error"); } - } else if (memcmp(command, "import ", 7) == 0) { + } + else if (memcmp(command, "import ", 7) == 0) { importCard(&command[7]); - } else if (memcmp(command, "set ", 4) == 0) { - const char* config = &command[4]; + } + else if (memcmp(command, "set ", 4) == 0) { + const char *config = &command[4]; if (memcmp(config, "af ", 3) == 0) { _prefs.airtime_factor = atof(&config[3]); savePrefs(); Serial.println(" OK"); - } else if (memcmp(config, "name ", 5) == 0) { + } + else if (memcmp(config, "name ", 5) == 0) { StrHelper::strncpy(_prefs.node_name, &config[5], sizeof(_prefs.node_name)); savePrefs(); Serial.println(" OK"); - } else if (memcmp(config, "lat ", 4) == 0) { + } + else if (memcmp(config, "lat ", 4) == 0) { _prefs.node_lat = atof(&config[4]); savePrefs(); Serial.println(" OK"); - } else if (memcmp(config, "lon ", 4) == 0) { + } + else if (memcmp(config, "lon ", 4) == 0) { _prefs.node_lon = atof(&config[4]); savePrefs(); Serial.println(" OK"); - } else if (memcmp(config, "tx ", 3) == 0) { + } + else if (memcmp(config, "tx ", 3) == 0) { _prefs.tx_power_dbm = atoi(&config[3]); savePrefs(); Serial.println(" OK - reboot to apply"); - } else if (memcmp(config, "freq ", 5) == 0) { + } + else if (memcmp(config, "freq ", 5) == 0) { _prefs.freq = atof(&config[5]); savePrefs(); Serial.println(" OK - reboot to apply"); - } else { + } + else { Serial.printf(" ERROR: unknown config: %s\n", config); } - } else if (memcmp(command, "ver", 3) == 0) { + } + else if (memcmp(command, "ver", 3) == 0) { Serial.println(FIRMWARE_VER_TEXT); - } else if (memcmp(command, "help", 4) == 0) { + } + else if (memcmp(command, "help", 4) == 0) { Serial.println("Commands:"); Serial.println(" set {name|lat|lon|freq|tx|af} {value}"); Serial.println(" card"); @@ -516,50 +584,59 @@ class MyMesh : public BaseChatMesh, ContactVisitor { Serial.println(" advert"); Serial.println(" reset path"); Serial.println(" public "); - } else { - Serial.print(" ERROR: unknown command: "); Serial.println(command); + } + else { + Serial.print(" ERROR: unknown command: "); + Serial.println(command); } } - void loop() { + void loop() + { BaseChatMesh::loop(); int len = strlen(command); - while (Serial.available() && len < sizeof(command)-1) { + while (Serial.available() && len < sizeof(command) - 1) { char c = Serial.read(); - if (c != '\n') { + if (c != '\n') { command[len++] = c; command[len] = 0; } Serial.print(c); } - if (len == sizeof(command)-1) { // command buffer full - command[sizeof(command)-1] = '\r'; + if (len == sizeof(command) - 1) { // command buffer full + command[sizeof(command) - 1] = '\r'; } - if (len > 0 && command[len - 1] == '\r') { // received complete line - command[len - 1] = 0; // replace newline with C string null terminator + if (len > 0 && command[len - 1] == '\r') { // received complete line + command[len - 1] = 0; // replace newline with C string null terminator handleCommand(command); - command[0] = 0; // reset command buffer + command[0] = 0; // reset command buffer } } }; StdRNG fast_rng; SimpleMeshTables tables; -MyMesh the_mesh(radio_driver, fast_rng, *new VolatileRTCClock(), tables); // TODO: test with 'rtc_clock' in target.cpp +MyMesh the_mesh(radio_driver, fast_rng, *new VolatileRTCClock(), + tables); // TODO: test with 'rtc_clock' in target.cpp -void halt() { - while (1) ; +void halt() +{ + while (1) + ; } -void setup() { +void setup() +{ Serial.begin(115200); board.begin(); - if (!radio_init()) { halt(); } + if (!radio_init()) { + halt(); + } fast_rng.begin(radio_get_rng_seed()); @@ -573,7 +650,7 @@ void setup() { SPIFFS.begin(true); the_mesh.begin(SPIFFS); #else - #error "need to define filesystem" +#error "need to define filesystem" #endif radio_set_params(the_mesh.getFreqPref(), LORA_BW, LORA_SF, LORA_CR); @@ -582,9 +659,10 @@ void setup() { the_mesh.showWelcome(); // send out initial Advertisement to the mesh - the_mesh.sendSelfAdvert(1200); // add slight delay + the_mesh.sendSelfAdvert(1200); // add slight delay } -void loop() { +void loop() +{ the_mesh.loop(); } From 9959475c0d908f477d82a2fe166d49b905ead289 Mon Sep 17 00:00:00 2001 From: hank Date: Sun, 1 Jun 2025 09:25:17 -0700 Subject: [PATCH 05/19] Reformatting code --- examples/companion_radio/MyMesh.cpp | 788 +++++++++++---------------- examples/companion_radio/MyMesh.h | 358 +++++------- examples/companion_radio/NodePrefs.h | 16 +- examples/companion_radio/UITask.h | 47 +- 4 files changed, 503 insertions(+), 706 deletions(-) diff --git a/examples/companion_radio/MyMesh.cpp b/examples/companion_radio/MyMesh.cpp index 6e9688a53..db40169f9 100644 --- a/examples/companion_radio/MyMesh.cpp +++ b/examples/companion_radio/MyMesh.cpp @@ -1,19 +1,83 @@ +#include "MyMesh.h" + #include // needed for PlatformIO #include -#include "MyMesh.h" + +#define CMD_APP_START 1 +#define CMD_SEND_TXT_MSG 2 +#define CMD_SEND_CHANNEL_TXT_MSG 3 +#define CMD_GET_CONTACTS 4 // with optional 'since' (for efficient sync) +#define CMD_GET_DEVICE_TIME 5 +#define CMD_SET_DEVICE_TIME 6 +#define CMD_SEND_SELF_ADVERT 7 +#define CMD_SET_ADVERT_NAME 8 +#define CMD_ADD_UPDATE_CONTACT 9 +#define CMD_SYNC_NEXT_MESSAGE 10 +#define CMD_SET_RADIO_PARAMS 11 +#define CMD_SET_RADIO_TX_POWER 12 +#define CMD_RESET_PATH 13 +#define CMD_SET_ADVERT_LATLON 14 +#define CMD_REMOVE_CONTACT 15 +#define CMD_SHARE_CONTACT 16 +#define CMD_EXPORT_CONTACT 17 +#define CMD_IMPORT_CONTACT 18 +#define CMD_REBOOT 19 +#define CMD_GET_BATTERY_VOLTAGE 20 +#define CMD_SET_TUNING_PARAMS 21 +#define CMD_DEVICE_QEURY 22 +#define CMD_EXPORT_PRIVATE_KEY 23 +#define CMD_IMPORT_PRIVATE_KEY 24 +#define CMD_SEND_RAW_DATA 25 +#define CMD_SEND_LOGIN 26 +#define CMD_SEND_STATUS_REQ 27 +#define CMD_HAS_CONNECTION 28 +#define CMD_LOGOUT 29 // 'Disconnect' +#define CMD_GET_CONTACT_BY_KEY 30 +#define CMD_GET_CHANNEL 31 +#define CMD_SET_CHANNEL 32 +#define CMD_SIGN_START 33 +#define CMD_SIGN_DATA 34 +#define CMD_SIGN_FINISH 35 +#define CMD_SEND_TRACE_PATH 36 +#define CMD_SET_DEVICE_PIN 37 +#define CMD_SET_OTHER_PARAMS 38 +#define CMD_SEND_TELEMETRY_REQ 39 +#define CMD_GET_CUSTOM_VARS 40 +#define CMD_SET_CUSTOM_VAR 41 + +#define RESP_CODE_OK 0 +#define RESP_CODE_ERR 1 +#define RESP_CODE_CONTACTS_START 2 // first reply to CMD_GET_CONTACTS +#define RESP_CODE_CONTACT 3 // multiple of these (after CMD_GET_CONTACTS) +#define RESP_CODE_END_OF_CONTACTS 4 // last reply to CMD_GET_CONTACTS +#define RESP_CODE_SELF_INFO 5 // reply to CMD_APP_START +#define RESP_CODE_SENT 6 // reply to CMD_SEND_TXT_MSG +#define RESP_CODE_CONTACT_MSG_RECV 7 // a reply to CMD_SYNC_NEXT_MESSAGE (ver < 3) +#define RESP_CODE_CHANNEL_MSG_RECV 8 // a reply to CMD_SYNC_NEXT_MESSAGE (ver < 3) +#define RESP_CODE_CURR_TIME 9 // a reply to CMD_GET_DEVICE_TIME +#define RESP_CODE_NO_MORE_MESSAGES 10 // a reply to CMD_SYNC_NEXT_MESSAGE +#define RESP_CODE_EXPORT_CONTACT 11 +#define RESP_CODE_BATTERY_VOLTAGE 12 // a reply to a CMD_GET_BATTERY_VOLTAGE +#define RESP_CODE_DEVICE_INFO 13 // a reply to CMD_DEVICE_QEURY +#define RESP_CODE_PRIVATE_KEY 14 // a reply to CMD_EXPORT_PRIVATE_KEY +#define RESP_CODE_DISABLED 15 +#define RESP_CODE_CONTACT_MSG_RECV_V3 16 // a reply to CMD_SYNC_NEXT_MESSAGE (ver >= 3) +#define RESP_CODE_CHANNEL_MSG_RECV_V3 17 // a reply to CMD_SYNC_NEXT_MESSAGE (ver >= 3) +#define RESP_CODE_CHANNEL_INFO 18 // a reply to CMD_GET_CHANNEL +#define RESP_CODE_SIGN_START 19 +#define RESP_CODE_SIGNATURE 20 +#define RESP_CODE_CUSTOM_VARS 21 #ifdef DISPLAY_CLASS - #include "UITask.h" +#include "UITask.h" #endif void MyMesh::loadMainIdentity() { - if (!_identity_store->load("_main", self_id)) - { + if (!_identity_store->load("_main", self_id)) { self_id = radio_new_identity(); // create new random identity int count = 0; - while (count < 10 && (self_id.pub_key[0] == 0x00 || self_id.pub_key[0] == 0xFF)) - { // reserved id hashes + while (count < 10 && (self_id.pub_key[0] == 0x00 || self_id.pub_key[0] == 0xFF)) { // reserved id hashes self_id = radio_new_identity(); count++; } @@ -28,18 +92,15 @@ bool MyMesh::saveMainIdentity(const mesh::LocalIdentity &identity) void MyMesh::loadContacts() { - if (_fs->exists("/contacts3")) - { + if (_fs->exists("/contacts3")) { #if defined(RP2040_PLATFORM) File file = _fs->open("/contacts3", "r"); #else File file = _fs->open("/contacts3"); #endif - if (file) - { + if (file) { bool full = false; - while (!full) - { + while (!full) { ContactInfo c; uint8_t pub_key[32]; uint8_t unused; @@ -79,14 +140,12 @@ void MyMesh::saveContacts() #else File file = _fs->open("/contacts3", "w", true); #endif - if (file) - { + if (file) { ContactsIterator iter; ContactInfo c; uint8_t unused = 0; - while (iter.hasNext(this, c)) - { + while (iter.hasNext(this, c)) { bool success = (file.write(c.id.pub_key, 32) == 32); success = success && (file.write((uint8_t *)&c.name, 32) == 32); success = success && (file.write(&c.type, 1) == 1); @@ -109,19 +168,16 @@ void MyMesh::saveContacts() void MyMesh::loadChannels() { - if (_fs->exists("/channels2")) - { + if (_fs->exists("/channels2")) { #if defined(RP2040_PLATFORM) File file = _fs->open("/channels2", "r"); #else File file = _fs->open("/channels2"); #endif - if (file) - { + if (file) { bool full = false; uint8_t channel_idx = 0; - while (!full) - { + while (!full) { ChannelDetails ch; uint8_t unused[4]; @@ -132,12 +188,10 @@ void MyMesh::loadChannels() if (!success) break; // EOF - if (setChannel(channel_idx, ch)) - { + if (setChannel(channel_idx, ch)) { channel_idx++; } - else - { + else { full = true; } } @@ -156,15 +210,13 @@ void MyMesh::saveChannels() #else File file = _fs->open("/channels2", "w", true); #endif - if (file) - { + if (file) { uint8_t channel_idx = 0; ChannelDetails ch; uint8_t unused[4]; memset(unused, 0, 4); - while (getChannel(channel_idx, ch)) - { + while (getChannel(channel_idx, ch)) { bool success = (file.write(unused, 4) == 4); success = success && (file.write((uint8_t *)ch.name, 32) == 32); success = success && (file.write((uint8_t *)ch.channel.secret, 32) == 32); @@ -187,15 +239,13 @@ int MyMesh::getBlobByKey(const uint8_t key[], int key_len, uint8_t dest_buf[]) mesh::Utils::toHex(fname, key, key_len); sprintf(path, "/bl/%s", fname); - if (_fs->exists(path)) - { + if (_fs->exists(path)) { #if defined(RP2040_PLATFORM) File f = _fs->open(path, "r"); #else File f = _fs->open(path); #endif - if (f) - { + if (f) { int len = f.read(dest_buf, 255); // currently MAX 255 byte blob len supported!! f.close(); return len; @@ -222,8 +272,7 @@ bool MyMesh::putBlobByKey(const uint8_t key[], int key_len, const uint8_t src_bu #else File f = _fs->open(path, "w", true); #endif - if (f) - { + if (f) { int n = f.write(src_buf, len); f.close(); if (n == len) @@ -294,8 +343,7 @@ void MyMesh::updateContactFromFrame(ContactInfo &contact, const uint8_t *frame, i += 32; memcpy(&contact.last_advert_timestamp, &frame[i], 4); i += 4; - if (i + 8 >= len) - { // optional fields + if (i + 8 >= len) { // optional fields memcpy(&contact.gps_lat, &frame[i], 4); i += 4; memcpy(&contact.gps_lon, &frame[i], 4); @@ -305,12 +353,10 @@ void MyMesh::updateContactFromFrame(ContactInfo &contact, const uint8_t *frame, void MyMesh::addToOfflineQueue(const uint8_t frame[], int len) { - if (offline_queue_len >= OFFLINE_QUEUE_SIZE) - { + if (offline_queue_len >= OFFLINE_QUEUE_SIZE) { MESH_DEBUG_PRINTLN("ERROR: offline_queue is full!"); } - else - { + else { offline_queue[offline_queue_len].len = len; memcpy(offline_queue[offline_queue_len].buf, frame, len); offline_queue_len++; @@ -318,14 +364,12 @@ void MyMesh::addToOfflineQueue(const uint8_t frame[], int len) } int MyMesh::getFromOfflineQueue(uint8_t frame[]) { - if (offline_queue_len > 0) - { // check offline queue + if (offline_queue_len > 0) { // check offline queue size_t len = offline_queue[0].len; // take from top of queue memcpy(frame, offline_queue[0].buf, len); offline_queue_len--; - for (int i = 0; i < offline_queue_len; i++) - { // delete top item from queue + for (int i = 0; i < offline_queue_len; i++) { // delete top item from queue offline_queue[i] = offline_queue[i + 1]; } return len; @@ -352,8 +396,7 @@ int MyMesh::calcRxDelay(float score, uint32_t air_time) const void MyMesh::logRxRaw(float snr, float rssi, const uint8_t raw[], int len) { - if (_serial->isConnected() && len + 3 <= MAX_FRAME_SIZE) - { + if (_serial->isConnected() && len + 3 <= MAX_FRAME_SIZE) { int i = 0; out_frame[i++] = PUSH_CODE_LOG_RX_DATA; out_frame[i++] = (int8_t)(snr * 4); @@ -372,21 +415,17 @@ bool MyMesh::isAutoAddEnabled() const void MyMesh::onDiscoveredContact(ContactInfo &contact, bool is_new) { - if (_serial->isConnected()) - { - if (!isAutoAddEnabled() && is_new) - { + if (_serial->isConnected()) { + if (!isAutoAddEnabled() && is_new) { writeContactRespFrame(PUSH_CODE_NEW_ADVERT, contact); } - else - { + else { out_frame[0] = PUSH_CODE_ADVERT; memcpy(&out_frame[1], contact.id.pub_key, PUB_KEY_SIZE); _serial->writeFrame(out_frame, 1 + PUB_KEY_SIZE); } } - else - { + else { #ifdef DISPLAY_CLASS ui_task.soundBuzzer(UIEventType::newContactMessage); #endif @@ -407,10 +446,8 @@ void MyMesh::onContactPathUpdated(const ContactInfo &contact) bool MyMesh::processAck(const uint8_t *data) { // see if matches any in a table - for (int i = 0; i < EXPECTED_ACK_TABLE_SIZE; i++) - { - if (memcmp(data, &expected_ack_table[i].ack, 4) == 0) - { // got an ACK from recipient + for (int i = 0; i < EXPECTED_ACK_TABLE_SIZE; i++) { + if (memcmp(data, &expected_ack_table[i].ack, 4) == 0) { // got an ACK from recipient out_frame[0] = PUSH_CODE_SEND_CONFIRMED; memcpy(&out_frame[1], data, 4); uint32_t trip_time = _ms->getMillis() - expected_ack_table[i].msg_sent; @@ -425,18 +462,17 @@ bool MyMesh::processAck(const uint8_t *data) return checkConnectionsAck(data); } -void MyMesh::queueMessage(const ContactInfo &from, uint8_t txt_type, mesh::Packet *pkt, uint32_t sender_timestamp, const uint8_t *extra, int extra_len, const char *text) +void MyMesh::queueMessage(const ContactInfo &from, uint8_t txt_type, mesh::Packet *pkt, + uint32_t sender_timestamp, const uint8_t *extra, int extra_len, const char *text) { int i = 0; - if (app_target_ver >= 3) - { + if (app_target_ver >= 3) { out_frame[i++] = RESP_CODE_CONTACT_MSG_RECV_V3; out_frame[i++] = (int8_t)(pkt->getSNR() * 4); out_frame[i++] = 0; // reserved1 out_frame[i++] = 0; // reserved2 } - else - { + else { out_frame[i++] = RESP_CODE_CONTACT_MSG_RECV; } memcpy(&out_frame[i], from.id.pub_key, 6); @@ -445,28 +481,24 @@ void MyMesh::queueMessage(const ContactInfo &from, uint8_t txt_type, mesh::Packe out_frame[i++] = txt_type; memcpy(&out_frame[i], &sender_timestamp, 4); i += 4; - if (extra_len > 0) - { + if (extra_len > 0) { memcpy(&out_frame[i], extra, extra_len); i += extra_len; } int tlen = strlen(text); // TODO: UTF-8 ?? - if (i + tlen > MAX_FRAME_SIZE) - { + if (i + tlen > MAX_FRAME_SIZE) { tlen = MAX_FRAME_SIZE - i; } memcpy(&out_frame[i], text, tlen); i += tlen; addToOfflineQueue(out_frame, i); - if (_serial->isConnected()) - { + if (_serial->isConnected()) { uint8_t frame[1]; frame[0] = PUSH_CODE_MSG_WAITING; // send push 'tickle' _serial->writeFrame(frame, 1); } - else - { + else { #ifdef DISPLAY_CLASS ui_task.soundBuzzer(UIEventType::contactMessage); #endif @@ -476,19 +508,22 @@ void MyMesh::queueMessage(const ContactInfo &from, uint8_t txt_type, mesh::Packe #endif } -void MyMesh::onMessageRecv(const ContactInfo &from, mesh::Packet *pkt, uint32_t sender_timestamp, const char *text) +void MyMesh::onMessageRecv(const ContactInfo &from, mesh::Packet *pkt, uint32_t sender_timestamp, + const char *text) { markConnectionActive(from); // in case this is from a server, and we have a connection queueMessage(from, TXT_TYPE_PLAIN, pkt, sender_timestamp, NULL, 0, text); } -void MyMesh::onCommandDataRecv(const ContactInfo &from, mesh::Packet *pkt, uint32_t sender_timestamp, const char *text) +void MyMesh::onCommandDataRecv(const ContactInfo &from, mesh::Packet *pkt, uint32_t sender_timestamp, + const char *text) { markConnectionActive(from); // in case this is from a server, and we have a connection queueMessage(from, TXT_TYPE_CLI_DATA, pkt, sender_timestamp, NULL, 0, text); } -void MyMesh::onSignedMessageRecv(const ContactInfo &from, mesh::Packet *pkt, uint32_t sender_timestamp, const uint8_t *sender_prefix, const char *text) +void MyMesh::onSignedMessageRecv(const ContactInfo &from, mesh::Packet *pkt, uint32_t sender_timestamp, + const uint8_t *sender_prefix, const char *text) { markConnectionActive(from); // from.sync_since change needs to be persisted @@ -496,18 +531,17 @@ void MyMesh::onSignedMessageRecv(const ContactInfo &from, mesh::Packet *pkt, uin queueMessage(from, TXT_TYPE_SIGNED_PLAIN, pkt, sender_timestamp, sender_prefix, 4, text); } -void MyMesh::onChannelMessageRecv(const mesh::GroupChannel &channel, mesh::Packet *pkt, uint32_t timestamp, const char *text) +void MyMesh::onChannelMessageRecv(const mesh::GroupChannel &channel, mesh::Packet *pkt, uint32_t timestamp, + const char *text) { int i = 0; - if (app_target_ver >= 3) - { + if (app_target_ver >= 3) { out_frame[i++] = RESP_CODE_CHANNEL_MSG_RECV_V3; out_frame[i++] = (int8_t)(pkt->getSNR() * 4); out_frame[i++] = 0; // reserved1 out_frame[i++] = 0; // reserved2 } - else - { + else { out_frame[i++] = RESP_CODE_CHANNEL_MSG_RECV; } @@ -518,22 +552,19 @@ void MyMesh::onChannelMessageRecv(const mesh::GroupChannel &channel, mesh::Packe memcpy(&out_frame[i], ×tamp, 4); i += 4; int tlen = strlen(text); // TODO: UTF-8 ?? - if (i + tlen > MAX_FRAME_SIZE) - { + if (i + tlen > MAX_FRAME_SIZE) { tlen = MAX_FRAME_SIZE - i; } memcpy(&out_frame[i], text, tlen); i += tlen; addToOfflineQueue(out_frame, i); - if (_serial->isConnected()) - { + if (_serial->isConnected()) { uint8_t frame[1]; frame[0] = PUSH_CODE_MSG_WAITING; // send push 'tickle' _serial->writeFrame(frame, 1); } - else - { + else { #ifdef DISPLAY_CLASS ui_task.soundBuzzer(UIEventType::channelMessage); #endif @@ -543,48 +574,42 @@ void MyMesh::onChannelMessageRecv(const mesh::GroupChannel &channel, mesh::Packe #endif } -uint8_t MyMesh::onContactRequest(const ContactInfo &contact, uint32_t sender_timestamp, const uint8_t *data, uint8_t len, uint8_t *reply) +uint8_t MyMesh::onContactRequest(const ContactInfo &contact, uint32_t sender_timestamp, const uint8_t *data, + uint8_t len, uint8_t *reply) { - if (data[0] == REQ_TYPE_GET_TELEMETRY_DATA) - { + if (data[0] == REQ_TYPE_GET_TELEMETRY_DATA) { uint8_t permissions = 0; uint8_t cp = contact.flags >> 1; // LSB used as 'favourite' bit (so only use upper bits) - if (_prefs.telemetry_mode_base == TELEM_MODE_ALLOW_ALL) - { + if (_prefs.telemetry_mode_base == TELEM_MODE_ALLOW_ALL) { permissions = TELEM_PERM_BASE; } - else if (_prefs.telemetry_mode_base == TELEM_MODE_ALLOW_FLAGS) - { + else if (_prefs.telemetry_mode_base == TELEM_MODE_ALLOW_FLAGS) { permissions = cp & TELEM_PERM_BASE; } - if (_prefs.telemetry_mode_loc == TELEM_MODE_ALLOW_ALL) - { + if (_prefs.telemetry_mode_loc == TELEM_MODE_ALLOW_ALL) { permissions |= TELEM_PERM_LOCATION; } - else if (_prefs.telemetry_mode_loc == TELEM_MODE_ALLOW_FLAGS) - { + else if (_prefs.telemetry_mode_loc == TELEM_MODE_ALLOW_FLAGS) { permissions |= cp & TELEM_PERM_LOCATION; } - if (_prefs.telemetry_mode_env == TELEM_MODE_ALLOW_ALL) - { + if (_prefs.telemetry_mode_env == TELEM_MODE_ALLOW_ALL) { permissions |= TELEM_PERM_ENVIRONMENT; } - else if (_prefs.telemetry_mode_env == TELEM_MODE_ALLOW_FLAGS) - { + else if (_prefs.telemetry_mode_env == TELEM_MODE_ALLOW_FLAGS) { permissions |= cp & TELEM_PERM_ENVIRONMENT; } - if (permissions & TELEM_PERM_BASE) - { // only respond if base permission bit is set + if (permissions & TELEM_PERM_BASE) { // only respond if base permission bit is set telemetry.reset(); telemetry.addVoltage(TELEM_CHANNEL_SELF, (float)board.getBattMilliVolts() / 1000.0f); // query other sensors -- target specific sensors.querySensors(permissions, telemetry); - memcpy(reply, &sender_timestamp, 4); // reflect sender_timestamp back in response packet (kind of like a 'tag') + memcpy(reply, &sender_timestamp, + 4); // reflect sender_timestamp back in response packet (kind of like a 'tag') uint8_t tlen = telemetry.getSize(); memcpy(&reply[4], telemetry.getBuffer(), tlen); @@ -599,24 +624,20 @@ void MyMesh::onContactResponse(const ContactInfo &contact, const uint8_t *data, uint32_t tag; memcpy(&tag, data, 4); - if (pending_login && memcmp(&pending_login, contact.id.pub_key, 4) == 0) - { // check for login response + if (pending_login && memcmp(&pending_login, contact.id.pub_key, 4) == 0) { // check for login response // yes, is response to pending sendLogin() pending_login = 0; int i = 0; - if (memcmp(&data[4], "OK", 2) == 0) - { // legacy Repeater login OK response + if (memcmp(&data[4], "OK", 2) == 0) { // legacy Repeater login OK response out_frame[i++] = PUSH_CODE_LOGIN_SUCCESS; out_frame[i++] = 0; // legacy: is_admin = false memcpy(&out_frame[i], contact.id.pub_key, 6); i += 6; // pub_key_prefix } - else if (data[4] == RESP_SERVER_LOGIN_OK) - { // new login response + else if (data[4] == RESP_SERVER_LOGIN_OK) { // new login response uint16_t keep_alive_secs = ((uint16_t)data[5]) * 16; - if (keep_alive_secs > 0) - { + if (keep_alive_secs > 0) { startConnection(contact, keep_alive_secs); } out_frame[i++] = PUSH_CODE_LOGIN_SUCCESS; @@ -626,8 +647,7 @@ void MyMesh::onContactResponse(const ContactInfo &contact, const uint8_t *data, memcpy(&out_frame[i], &tag, 4); i += 4; // NEW: include server timestamp } - else - { + else { out_frame[i++] = PUSH_CODE_LOGIN_FAIL; out_frame[i++] = 0; // reserved memcpy(&out_frame[i], contact.id.pub_key, 6); @@ -635,11 +655,11 @@ void MyMesh::onContactResponse(const ContactInfo &contact, const uint8_t *data, } _serial->writeFrame(out_frame, i); } - else if (len > 4 && // check for status response - pending_status && memcmp(&pending_status, contact.id.pub_key, 4) == 0 // legacy matching scheme - // FUTURE: tag == pending_status - ) - { + else if (len > 4 && // check for status response + pending_status && + memcmp(&pending_status, contact.id.pub_key, 4) == 0 // legacy matching scheme + // FUTURE: tag == pending_status + ) { pending_status = 0; int i = 0; @@ -651,8 +671,7 @@ void MyMesh::onContactResponse(const ContactInfo &contact, const uint8_t *data, i += (len - 4); _serial->writeFrame(out_frame, i); } - else if (len > 4 && tag == pending_telemetry) - { // check for telemetry response + else if (len > 4 && tag == pending_telemetry) { // check for telemetry response pending_telemetry = 0; int i = 0; @@ -668,8 +687,7 @@ void MyMesh::onContactResponse(const ContactInfo &contact, const uint8_t *data, void MyMesh::onRawDataRecv(mesh::Packet *packet) { - if (packet->payload_len + 4 > sizeof(out_frame)) - { + if (packet->payload_len + 4 > sizeof(out_frame)) { MESH_DEBUG_PRINTLN("onRawDataRecv(), payload_len too long: %d", packet->payload_len); return; } @@ -681,17 +699,16 @@ void MyMesh::onRawDataRecv(mesh::Packet *packet) memcpy(&out_frame[i], packet->payload, packet->payload_len); i += packet->payload_len; - if (_serial->isConnected()) - { + if (_serial->isConnected()) { _serial->writeFrame(out_frame, i); } - else - { + else { MESH_DEBUG_PRINTLN("onRawDataRecv(), data received while app offline"); } } -void MyMesh::onTraceRecv(mesh::Packet *packet, uint32_t tag, uint32_t auth_code, uint8_t flags, const uint8_t *path_snrs, const uint8_t *path_hashes, uint8_t path_len) +void MyMesh::onTraceRecv(mesh::Packet *packet, uint32_t tag, uint32_t auth_code, uint8_t flags, + const uint8_t *path_snrs, const uint8_t *path_hashes, uint8_t path_len) { int i = 0; out_frame[i++] = PUSH_CODE_TRACE_DATA; @@ -708,12 +725,10 @@ void MyMesh::onTraceRecv(mesh::Packet *packet, uint32_t tag, uint32_t auth_code, i += path_len; out_frame[i++] = (int8_t)(packet->getSNR() * 4); // extra/final SNR (to this node) - if (_serial->isConnected()) - { + if (_serial->isConnected()) { _serial->writeFrame(out_frame, i); } - else - { + else { MESH_DEBUG_PRINTLN("onTraceRecv(), data received while app offline"); } } @@ -725,16 +740,15 @@ uint32_t MyMesh::calcFloodTimeoutMillisFor(uint32_t pkt_airtime_millis) const uint32_t MyMesh::calcDirectTimeoutMillisFor(uint32_t pkt_airtime_millis, uint8_t path_len) const { return SEND_TIMEOUT_BASE_MILLIS + - ((pkt_airtime_millis * DIRECT_SEND_PERHOP_FACTOR + DIRECT_SEND_PERHOP_EXTRA_MILLIS) * (path_len + 1)); + ((pkt_airtime_millis * DIRECT_SEND_PERHOP_FACTOR + DIRECT_SEND_PERHOP_EXTRA_MILLIS) * + (path_len + 1)); } -void MyMesh::onSendTimeout() -{ -} +void MyMesh::onSendTimeout() {} MyMesh::MyMesh(mesh::Radio &radio, mesh::RNG &rng, mesh::RTCClock &rtc, SimpleMeshTables &tables) - : BaseChatMesh(radio, *new ArduinoMillis(), rng, rtc, *new StaticPoolPacketManager(16), tables), _serial(NULL), - telemetry(MAX_PACKET_PAYLOAD - 4) + : BaseChatMesh(radio, *new ArduinoMillis(), rng, rtc, *new StaticPoolPacketManager(16), tables), + _serial(NULL), telemetry(MAX_PACKET_PAYLOAD - 4) { _iter_started = false; offline_queue_len = 0; @@ -764,8 +778,7 @@ void MyMesh::loadPrefsInt(const char *filename) #else File file = _fs->open(filename); #endif - if (file) - { + if (file) { uint8_t pad[8]; file.read((uint8_t *)&_prefs.airtime_factor, sizeof(float)); // 0 @@ -828,36 +841,30 @@ void MyMesh::begin(FILESYSTEM &fs, bool has_display) #endif // load persisted prefs - if (_fs->exists("/new_prefs")) - { + if (_fs->exists("/new_prefs")) { loadPrefsInt("/new_prefs"); // new filename } - else if (_fs->exists("/node_prefs")) - { + else if (_fs->exists("/node_prefs")) { loadPrefsInt("/node_prefs"); savePrefs(); // save to new filename _fs->remove("/node_prefs"); // remove old } #ifdef BLE_PIN_CODE - if (_prefs.ble_pin == 0) - { + if (_prefs.ble_pin == 0) { #ifdef DISPLAY_CLASS - if (has_display) - { + if (has_display) { StdRNG rng; _active_ble_pin = rng.nextInt(100000, 999999); // random pin each session } - else - { + else { _active_ble_pin = BLE_PIN_CODE; // otherwise static pin } #else _active_ble_pin = BLE_PIN_CODE; // otherwise static pin #endif } - else - { + else { _active_ble_pin = _prefs.ble_pin; } #else @@ -875,12 +882,18 @@ void MyMesh::begin(FILESYSTEM &fs, bool has_display) radio_set_tx_power(_prefs.tx_power_dbm); } -const char *MyMesh::getNodeName() { return _prefs.node_name; } +const char *MyMesh::getNodeName() +{ + return _prefs.node_name; +} NodePrefs *MyMesh::getNodePrefs() { return &_prefs; } -uint32_t MyMesh::getBLEPin() { return _active_ble_pin; } +uint32_t MyMesh::getBLEPin() +{ + return _active_ble_pin; +} void MyMesh::startInterface(BaseSerialInterface &serial) { @@ -898,8 +911,7 @@ void MyMesh::savePrefs() #else File file = _fs->open("/new_prefs", "w", true); #endif - if (file) - { + if (file) { uint8_t pad[8]; memset(pad, 0, sizeof(pad)); @@ -928,9 +940,8 @@ void MyMesh::savePrefs() void MyMesh::handleCmdFrame(size_t len) { - if (cmd_frame[0] == CMD_DEVICE_QEURY && len >= 2) - { // sent when app establishes connection - app_target_ver = cmd_frame[1]; // which version of protocol does app understand + if (cmd_frame[0] == CMD_DEVICE_QEURY && len >= 2) { // sent when app establishes connection + app_target_ver = cmd_frame[1]; // which version of protocol does app understand int i = 0; out_frame[i++] = RESP_CODE_DEVICE_INFO; @@ -948,8 +959,8 @@ void MyMesh::handleCmdFrame(size_t len) i += 20; _serial->writeFrame(out_frame, i); } - else if (cmd_frame[0] == CMD_APP_START && len >= 8) - { // sent when app establishes connection, respond with node ID + else if (cmd_frame[0] == CMD_APP_START && + len >= 8) { // sent when app establishes connection, respond with node ID // cmd_frame[1..7] reserved future char *app_name = (char *)&cmd_frame[8]; cmd_frame[len] = 0; // make app_name null terminated @@ -971,9 +982,10 @@ void MyMesh::handleCmdFrame(size_t len) i += 4; memcpy(&out_frame[i], &lon, 4); i += 4; - out_frame[i++] = 0; // reserved - out_frame[i++] = 0; // reserved - out_frame[i++] = (_prefs.telemetry_mode_env << 4) | (_prefs.telemetry_mode_loc << 2) | (_prefs.telemetry_mode_base); // v5+ + out_frame[i++] = 0; // reserved + out_frame[i++] = 0; // reserved + out_frame[i++] = (_prefs.telemetry_mode_env << 4) | (_prefs.telemetry_mode_loc << 2) | + (_prefs.telemetry_mode_base); // v5+ out_frame[i++] = _prefs.manual_add_contacts; uint32_t freq = _prefs.freq * 1000; @@ -990,8 +1002,7 @@ void MyMesh::handleCmdFrame(size_t len) i += tlen; _serial->writeFrame(out_frame, i); } - else if (cmd_frame[0] == CMD_SEND_TXT_MSG && len >= 14) - { + else if (cmd_frame[0] == CMD_SEND_TXT_MSG && len >= 14) { int i = 1; uint8_t txt_type = cmd_frame[i++]; uint8_t attempt = cmd_frame[i++]; @@ -1001,32 +1012,26 @@ void MyMesh::handleCmdFrame(size_t len) uint8_t *pub_key_prefix = &cmd_frame[i]; i += 6; ContactInfo *recipient = lookupContactByPubKey(pub_key_prefix, 6); - if (recipient && (txt_type == TXT_TYPE_PLAIN || txt_type == TXT_TYPE_CLI_DATA)) - { + if (recipient && (txt_type == TXT_TYPE_PLAIN || txt_type == TXT_TYPE_CLI_DATA)) { char *text = (char *)&cmd_frame[i]; int tlen = len - i; uint32_t est_timeout; text[tlen] = 0; // ensure null int result; uint32_t expected_ack; - if (txt_type == TXT_TYPE_CLI_DATA) - { + if (txt_type == TXT_TYPE_CLI_DATA) { result = sendCommandData(*recipient, msg_timestamp, attempt, text, est_timeout); expected_ack = 0; // no Ack expected } - else - { + else { result = sendMessage(*recipient, msg_timestamp, attempt, text, expected_ack, est_timeout); } // TODO: add expected ACK to table - if (result == MSG_SEND_FAILED) - { + if (result == MSG_SEND_FAILED) { writeErrFrame(ERR_CODE_TABLE_FULL); } - else - { - if (expected_ack) - { + else { + if (expected_ack) { expected_ack_table[next_ack_idx].msg_sent = _ms->getMillis(); // add to circular table expected_ack_table[next_ack_idx].ack = expected_ack; next_ack_idx = (next_ack_idx + 1) % EXPECTED_ACK_TABLE_SIZE; @@ -1039,13 +1044,13 @@ void MyMesh::handleCmdFrame(size_t len) _serial->writeFrame(out_frame, 10); } } - else - { - writeErrFrame(recipient == NULL ? ERR_CODE_NOT_FOUND : ERR_CODE_UNSUPPORTED_CMD); // unknown recipient, or unsuported TXT_TYPE_* + else { + writeErrFrame(recipient == NULL + ? ERR_CODE_NOT_FOUND + : ERR_CODE_UNSUPPORTED_CMD); // unknown recipient, or unsuported TXT_TYPE_* } } - else if (cmd_frame[0] == CMD_SEND_CHANNEL_TXT_MSG) - { // send GroupChannel msg + else if (cmd_frame[0] == CMD_SEND_CHANNEL_TXT_MSG) { // send GroupChannel msg int i = 1; uint8_t txt_type = cmd_frame[i++]; // should be TXT_TYPE_PLAIN uint8_t channel_idx = cmd_frame[i++]; @@ -1054,38 +1059,29 @@ void MyMesh::handleCmdFrame(size_t len) i += 4; const char *text = (char *)&cmd_frame[i]; - if (txt_type != TXT_TYPE_PLAIN) - { + if (txt_type != TXT_TYPE_PLAIN) { writeErrFrame(ERR_CODE_UNSUPPORTED_CMD); } - else - { + else { ChannelDetails channel; bool success = getChannel(channel_idx, channel); - if (success && sendGroupMessage(msg_timestamp, channel.channel, _prefs.node_name, text, len - i)) - { + if (success && sendGroupMessage(msg_timestamp, channel.channel, _prefs.node_name, text, len - i)) { writeOKFrame(); } - else - { + else { writeErrFrame(ERR_CODE_NOT_FOUND); // bad channel_idx } } } - else if (cmd_frame[0] == CMD_GET_CONTACTS) - { // get Contact list - if (_iter_started) - { + else if (cmd_frame[0] == CMD_GET_CONTACTS) { // get Contact list + if (_iter_started) { writeErrFrame(ERR_CODE_BAD_STATE); // iterator is currently busy } - else - { - if (len >= 5) - { // has optional 'since' param + else { + if (len >= 5) { // has optional 'since' param memcpy(&_iter_filter_since, &cmd_frame[1], 4); } - else - { + else { _iter_filter_since = 0; } @@ -1101,8 +1097,7 @@ void MyMesh::handleCmdFrame(size_t len) _most_recent_lastmod = 0; } } - else if (cmd_frame[0] == CMD_SET_ADVERT_NAME && len >= 2) - { + else if (cmd_frame[0] == CMD_SET_ADVERT_NAME && len >= 2) { int nlen = len - 1; if (nlen > sizeof(_prefs.node_name) - 1) nlen = sizeof(_prefs.node_name) - 1; // max len @@ -1111,169 +1106,134 @@ void MyMesh::handleCmdFrame(size_t len) savePrefs(); writeOKFrame(); } - else if (cmd_frame[0] == CMD_SET_ADVERT_LATLON && len >= 9) - { + else if (cmd_frame[0] == CMD_SET_ADVERT_LATLON && len >= 9) { int32_t lat, lon, alt = 0; memcpy(&lat, &cmd_frame[1], 4); memcpy(&lon, &cmd_frame[5], 4); - if (len >= 13) - { + if (len >= 13) { memcpy(&alt, &cmd_frame[9], 4); // for FUTURE support } - if (lat <= 90 * 1E6 && lat >= -90 * 1E6 && lon <= 180 * 1E6 && lon >= -180 * 1E6) - { + if (lat <= 90 * 1E6 && lat >= -90 * 1E6 && lon <= 180 * 1E6 && lon >= -180 * 1E6) { sensors.node_lat = ((double)lat) / 1000000.0; sensors.node_lon = ((double)lon) / 1000000.0; savePrefs(); writeOKFrame(); } - else - { + else { writeErrFrame(ERR_CODE_ILLEGAL_ARG); // invalid geo coordinate } } - else if (cmd_frame[0] == CMD_GET_DEVICE_TIME) - { + else if (cmd_frame[0] == CMD_GET_DEVICE_TIME) { uint8_t reply[5]; reply[0] = RESP_CODE_CURR_TIME; uint32_t now = getRTCClock()->getCurrentTime(); memcpy(&reply[1], &now, 4); _serial->writeFrame(reply, 5); } - else if (cmd_frame[0] == CMD_SET_DEVICE_TIME && len >= 5) - { + else if (cmd_frame[0] == CMD_SET_DEVICE_TIME && len >= 5) { uint32_t secs; memcpy(&secs, &cmd_frame[1], 4); uint32_t curr = getRTCClock()->getCurrentTime(); - if (secs >= curr) - { + if (secs >= curr) { getRTCClock()->setCurrentTime(secs); writeOKFrame(); } - else - { + else { writeErrFrame(ERR_CODE_ILLEGAL_ARG); } } - else if (cmd_frame[0] == CMD_SEND_SELF_ADVERT) - { + else if (cmd_frame[0] == CMD_SEND_SELF_ADVERT) { auto pkt = createSelfAdvert(_prefs.node_name, sensors.node_lat, sensors.node_lon); - if (pkt) - { - if (len >= 2 && cmd_frame[1] == 1) - { // optional param (1 = flood, 0 = zero hop) + if (pkt) { + if (len >= 2 && cmd_frame[1] == 1) { // optional param (1 = flood, 0 = zero hop) sendFlood(pkt); } - else - { + else { sendZeroHop(pkt); } writeOKFrame(); } - else - { + else { writeErrFrame(ERR_CODE_TABLE_FULL); } } - else if (cmd_frame[0] == CMD_RESET_PATH && len >= 1 + 32) - { + else if (cmd_frame[0] == CMD_RESET_PATH && len >= 1 + 32) { uint8_t *pub_key = &cmd_frame[1]; ContactInfo *recipient = lookupContactByPubKey(pub_key, PUB_KEY_SIZE); - if (recipient) - { + if (recipient) { recipient->out_path_len = -1; // recipient->lastmod = ?? shouldn't be needed, app already has this version of contact dirty_contacts_expiry = futureMillis(LAZY_CONTACTS_WRITE_DELAY); writeOKFrame(); } - else - { + else { writeErrFrame(ERR_CODE_NOT_FOUND); // unknown contact } } - else if (cmd_frame[0] == CMD_ADD_UPDATE_CONTACT && len >= 1 + 32 + 2 + 1) - { + else if (cmd_frame[0] == CMD_ADD_UPDATE_CONTACT && len >= 1 + 32 + 2 + 1) { uint8_t *pub_key = &cmd_frame[1]; ContactInfo *recipient = lookupContactByPubKey(pub_key, PUB_KEY_SIZE); - if (recipient) - { + if (recipient) { updateContactFromFrame(*recipient, cmd_frame, len); // recipient->lastmod = ?? shouldn't be needed, app already has this version of contact dirty_contacts_expiry = futureMillis(LAZY_CONTACTS_WRITE_DELAY); writeOKFrame(); } - else - { + else { ContactInfo contact; updateContactFromFrame(contact, cmd_frame, len); contact.lastmod = getRTCClock()->getCurrentTime(); contact.sync_since = 0; - if (addContact(contact)) - { + if (addContact(contact)) { dirty_contacts_expiry = futureMillis(LAZY_CONTACTS_WRITE_DELAY); writeOKFrame(); } - else - { + else { writeErrFrame(ERR_CODE_TABLE_FULL); } } } - else if (cmd_frame[0] == CMD_REMOVE_CONTACT) - { + else if (cmd_frame[0] == CMD_REMOVE_CONTACT) { uint8_t *pub_key = &cmd_frame[1]; ContactInfo *recipient = lookupContactByPubKey(pub_key, PUB_KEY_SIZE); - if (recipient && removeContact(*recipient)) - { + if (recipient && removeContact(*recipient)) { dirty_contacts_expiry = futureMillis(LAZY_CONTACTS_WRITE_DELAY); writeOKFrame(); } - else - { + else { writeErrFrame(ERR_CODE_NOT_FOUND); // not found, or unable to remove } } - else if (cmd_frame[0] == CMD_SHARE_CONTACT) - { + else if (cmd_frame[0] == CMD_SHARE_CONTACT) { uint8_t *pub_key = &cmd_frame[1]; ContactInfo *recipient = lookupContactByPubKey(pub_key, PUB_KEY_SIZE); - if (recipient) - { - if (shareContactZeroHop(*recipient)) - { + if (recipient) { + if (shareContactZeroHop(*recipient)) { writeOKFrame(); } - else - { + else { writeErrFrame(ERR_CODE_TABLE_FULL); // unable to send } } - else - { + else { writeErrFrame(ERR_CODE_NOT_FOUND); } } - else if (cmd_frame[0] == CMD_GET_CONTACT_BY_KEY) - { + else if (cmd_frame[0] == CMD_GET_CONTACT_BY_KEY) { uint8_t *pub_key = &cmd_frame[1]; ContactInfo *contact = lookupContactByPubKey(pub_key, PUB_KEY_SIZE); - if (contact) - { + if (contact) { writeContactRespFrame(RESP_CODE_CONTACT, *contact); } - else - { + else { writeErrFrame(ERR_CODE_NOT_FOUND); // not found } } - else if (cmd_frame[0] == CMD_EXPORT_CONTACT) - { - if (len < 1 + PUB_KEY_SIZE) - { + else if (cmd_frame[0] == CMD_EXPORT_CONTACT) { + if (len < 1 + PUB_KEY_SIZE) { // export SELF auto pkt = createSelfAdvert(_prefs.node_name, sensors.node_lat, sensors.node_lon); - if (pkt) - { + if (pkt) { pkt->header |= ROUTE_TYPE_FLOOD; // would normally be sent in this mode out_frame[0] = RESP_CODE_EXPORT_CONTACT; @@ -1281,56 +1241,45 @@ void MyMesh::handleCmdFrame(size_t len) releasePacket(pkt); // undo the obtainNewPacket() _serial->writeFrame(out_frame, out_len + 1); } - else - { + else { writeErrFrame(ERR_CODE_TABLE_FULL); // Error } } - else - { + else { uint8_t *pub_key = &cmd_frame[1]; ContactInfo *recipient = lookupContactByPubKey(pub_key, PUB_KEY_SIZE); uint8_t out_len; - if (recipient && (out_len = exportContact(*recipient, &out_frame[1])) > 0) - { + if (recipient && (out_len = exportContact(*recipient, &out_frame[1])) > 0) { out_frame[0] = RESP_CODE_EXPORT_CONTACT; _serial->writeFrame(out_frame, out_len + 1); } - else - { + else { writeErrFrame(ERR_CODE_NOT_FOUND); // not found } } } - else if (cmd_frame[0] == CMD_IMPORT_CONTACT && len > 2 + 32 + 64) - { - if (importContact(&cmd_frame[1], len - 1)) - { + else if (cmd_frame[0] == CMD_IMPORT_CONTACT && len > 2 + 32 + 64) { + if (importContact(&cmd_frame[1], len - 1)) { writeOKFrame(); } - else - { + else { writeErrFrame(ERR_CODE_ILLEGAL_ARG); } } - else if (cmd_frame[0] == CMD_SYNC_NEXT_MESSAGE) - { + else if (cmd_frame[0] == CMD_SYNC_NEXT_MESSAGE) { int out_len; - if ((out_len = getFromOfflineQueue(out_frame)) > 0) - { + if ((out_len = getFromOfflineQueue(out_frame)) > 0) { _serial->writeFrame(out_frame, out_len); #ifdef DISPLAY_CLASS ui_task.msgRead(offline_queue_len); #endif } - else - { + else { out_frame[0] = RESP_CODE_NO_MORE_MESSAGES; _serial->writeFrame(out_frame, 1); } } - else if (cmd_frame[0] == CMD_SET_RADIO_PARAMS) - { + else if (cmd_frame[0] == CMD_SET_RADIO_PARAMS) { int i = 1; uint32_t freq; memcpy(&freq, &cmd_frame[i], 4); @@ -1341,8 +1290,8 @@ void MyMesh::handleCmdFrame(size_t len) uint8_t sf = cmd_frame[i++]; uint8_t cr = cmd_frame[i++]; - if (freq >= 300000 && freq <= 2500000 && sf >= 7 && sf <= 12 && cr >= 5 && cr <= 8 && bw >= 7000 && bw <= 500000) - { + if (freq >= 300000 && freq <= 2500000 && sf >= 7 && sf <= 12 && cr >= 5 && cr <= 8 && bw >= 7000 && + bw <= 500000) { _prefs.sf = sf; _prefs.cr = cr; _prefs.freq = (float)freq / 1000.0; @@ -1350,32 +1299,29 @@ void MyMesh::handleCmdFrame(size_t len) savePrefs(); radio_set_params(_prefs.freq, _prefs.bw, _prefs.sf, _prefs.cr); - MESH_DEBUG_PRINTLN("OK: CMD_SET_RADIO_PARAMS: f=%d, bw=%d, sf=%d, cr=%d", freq, bw, (uint32_t)sf, (uint32_t)cr); + MESH_DEBUG_PRINTLN("OK: CMD_SET_RADIO_PARAMS: f=%d, bw=%d, sf=%d, cr=%d", freq, bw, (uint32_t)sf, + (uint32_t)cr); writeOKFrame(); } - else - { - MESH_DEBUG_PRINTLN("Error: CMD_SET_RADIO_PARAMS: f=%d, bw=%d, sf=%d, cr=%d", freq, bw, (uint32_t)sf, (uint32_t)cr); + else { + MESH_DEBUG_PRINTLN("Error: CMD_SET_RADIO_PARAMS: f=%d, bw=%d, sf=%d, cr=%d", freq, bw, (uint32_t)sf, + (uint32_t)cr); writeErrFrame(ERR_CODE_ILLEGAL_ARG); } } - else if (cmd_frame[0] == CMD_SET_RADIO_TX_POWER) - { - if (cmd_frame[1] > MAX_LORA_TX_POWER) - { + else if (cmd_frame[0] == CMD_SET_RADIO_TX_POWER) { + if (cmd_frame[1] > MAX_LORA_TX_POWER) { writeErrFrame(ERR_CODE_ILLEGAL_ARG); } - else - { + else { _prefs.tx_power_dbm = cmd_frame[1]; savePrefs(); radio_set_tx_power(_prefs.tx_power_dbm); writeOKFrame(); } } - else if (cmd_frame[0] == CMD_SET_TUNING_PARAMS) - { + else if (cmd_frame[0] == CMD_SET_TUNING_PARAMS) { int i = 1; uint32_t rx, af; memcpy(&rx, &cmd_frame[i], 4); @@ -1387,11 +1333,9 @@ void MyMesh::handleCmdFrame(size_t len) savePrefs(); writeOKFrame(); } - else if (cmd_frame[0] == CMD_SET_OTHER_PARAMS) - { + else if (cmd_frame[0] == CMD_SET_OTHER_PARAMS) { _prefs.manual_add_contacts = cmd_frame[1]; - if (len >= 3) - { + if (len >= 3) { _prefs.telemetry_mode_base = cmd_frame[2] & 0x03; // v5+ _prefs.telemetry_mode_loc = (cmd_frame[2] >> 2) & 0x03; _prefs.telemetry_mode_env = (cmd_frame[2] >> 4) & 0x03; @@ -1399,24 +1343,20 @@ void MyMesh::handleCmdFrame(size_t len) savePrefs(); writeOKFrame(); } - else if (cmd_frame[0] == CMD_REBOOT && memcmp(&cmd_frame[1], "reboot", 6) == 0) - { - if (dirty_contacts_expiry) - { // is there are pending dirty contacts write needed? + else if (cmd_frame[0] == CMD_REBOOT && memcmp(&cmd_frame[1], "reboot", 6) == 0) { + if (dirty_contacts_expiry) { // is there are pending dirty contacts write needed? saveContacts(); } board.reboot(); } - else if (cmd_frame[0] == CMD_GET_BATTERY_VOLTAGE) - { + else if (cmd_frame[0] == CMD_GET_BATTERY_VOLTAGE) { uint8_t reply[3]; reply[0] = RESP_CODE_BATTERY_VOLTAGE; uint16_t battery_millivolts = board.getBattMilliVolts(); memcpy(&reply[1], &battery_millivolts, 2); _serial->writeFrame(reply, 3); } - else if (cmd_frame[0] == CMD_EXPORT_PRIVATE_KEY) - { + else if (cmd_frame[0] == CMD_EXPORT_PRIVATE_KEY) { #if ENABLE_PRIVATE_KEY_EXPORT uint8_t reply[65]; reply[0] = RESP_CODE_PRIVATE_KEY; @@ -1426,64 +1366,52 @@ void MyMesh::handleCmdFrame(size_t len) writeDisabledFrame(); #endif } - else if (cmd_frame[0] == CMD_IMPORT_PRIVATE_KEY && len >= 65) - { + else if (cmd_frame[0] == CMD_IMPORT_PRIVATE_KEY && len >= 65) { #if ENABLE_PRIVATE_KEY_IMPORT mesh::LocalIdentity identity; identity.readFrom(&cmd_frame[1], 64); - if (saveMainIdentity(identity)) - { + if (saveMainIdentity(identity)) { self_id = identity; writeOKFrame(); } - else - { + else { writeErrFrame(ERR_CODE_FILE_IO_ERROR); } #else writeDisabledFrame(); #endif } - else if (cmd_frame[0] == CMD_SEND_RAW_DATA && len >= 6) - { + else if (cmd_frame[0] == CMD_SEND_RAW_DATA && len >= 6) { int i = 1; int8_t path_len = cmd_frame[i++]; - if (path_len >= 0 && i + path_len + 4 <= len) - { // minimum 4 byte payload + if (path_len >= 0 && i + path_len + 4 <= len) { // minimum 4 byte payload uint8_t *path = &cmd_frame[i]; i += path_len; auto pkt = createRawData(&cmd_frame[i], len - i); - if (pkt) - { + if (pkt) { sendDirect(pkt, path, path_len); writeOKFrame(); } - else - { + else { writeErrFrame(ERR_CODE_TABLE_FULL); } } - else - { + else { writeErrFrame(ERR_CODE_UNSUPPORTED_CMD); // flood, not supported (yet) } } - else if (cmd_frame[0] == CMD_SEND_LOGIN && len >= 1 + PUB_KEY_SIZE) - { + else if (cmd_frame[0] == CMD_SEND_LOGIN && len >= 1 + PUB_KEY_SIZE) { uint8_t *pub_key = &cmd_frame[1]; ContactInfo *recipient = lookupContactByPubKey(pub_key, PUB_KEY_SIZE); char *password = (char *)&cmd_frame[1 + PUB_KEY_SIZE]; cmd_frame[len] = 0; // ensure null terminator in password - if (recipient) - { + if (recipient) { uint32_t est_timeout; int result = sendLogin(*recipient, password, est_timeout); - if (result == MSG_SEND_FAILED) - { + if (result == MSG_SEND_FAILED) { writeErrFrame(ERR_CODE_TABLE_FULL); } - else - { + else { pending_telemetry = pending_status = 0; memcpy(&pending_login, recipient->id.pub_key, 4); // match this to onContactResponse() out_frame[0] = RESP_CODE_SENT; @@ -1493,25 +1421,20 @@ void MyMesh::handleCmdFrame(size_t len) _serial->writeFrame(out_frame, 10); } } - else - { + 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]; ContactInfo *recipient = lookupContactByPubKey(pub_key, PUB_KEY_SIZE); - if (recipient) - { + if (recipient) { uint32_t tag, est_timeout; int result = sendRequest(*recipient, REQ_TYPE_GET_STATUS, tag, est_timeout); - if (result == MSG_SEND_FAILED) - { + if (result == MSG_SEND_FAILED) { writeErrFrame(ERR_CODE_TABLE_FULL); } - else - { + else { pending_telemetry = pending_login = 0; // FUTURE: pending_status = tag; // match this in onContactResponse() memcpy(&pending_status, recipient->id.pub_key, 4); // legacy matching scheme @@ -1522,25 +1445,20 @@ void MyMesh::handleCmdFrame(size_t len) _serial->writeFrame(out_frame, 10); } } - else - { + else { writeErrFrame(ERR_CODE_NOT_FOUND); // contact not found } } - else if (cmd_frame[0] == CMD_SEND_TELEMETRY_REQ && len >= 4 + PUB_KEY_SIZE) - { + else if (cmd_frame[0] == CMD_SEND_TELEMETRY_REQ && len >= 4 + PUB_KEY_SIZE) { uint8_t *pub_key = &cmd_frame[4]; ContactInfo *recipient = lookupContactByPubKey(pub_key, PUB_KEY_SIZE); - if (recipient) - { + if (recipient) { uint32_t tag, est_timeout; int result = sendRequest(*recipient, REQ_TYPE_GET_TELEMETRY_DATA, tag, est_timeout); - if (result == MSG_SEND_FAILED) - { + if (result == MSG_SEND_FAILED) { writeErrFrame(ERR_CODE_TABLE_FULL); } - else - { + else { pending_status = pending_login = 0; pending_telemetry = tag; // match this in onContactResponse() out_frame[0] = RESP_CODE_SENT; @@ -1550,35 +1468,28 @@ void MyMesh::handleCmdFrame(size_t len) _serial->writeFrame(out_frame, 10); } } - else - { + else { writeErrFrame(ERR_CODE_NOT_FOUND); // contact not found } } - else if (cmd_frame[0] == CMD_HAS_CONNECTION && len >= 1 + PUB_KEY_SIZE) - { + else if (cmd_frame[0] == CMD_HAS_CONNECTION && len >= 1 + PUB_KEY_SIZE) { uint8_t *pub_key = &cmd_frame[1]; - if (hasConnectionTo(pub_key)) - { + if (hasConnectionTo(pub_key)) { writeOKFrame(); } - else - { + else { writeErrFrame(ERR_CODE_NOT_FOUND); } } - else if (cmd_frame[0] == CMD_LOGOUT && len >= 1 + PUB_KEY_SIZE) - { + else if (cmd_frame[0] == CMD_LOGOUT && len >= 1 + PUB_KEY_SIZE) { uint8_t *pub_key = &cmd_frame[1]; stopConnection(pub_key); writeOKFrame(); } - else if (cmd_frame[0] == CMD_GET_CHANNEL && len >= 2) - { + else if (cmd_frame[0] == CMD_GET_CHANNEL && len >= 2) { uint8_t channel_idx = cmd_frame[1]; ChannelDetails channel; - if (getChannel(channel_idx, channel)) - { + if (getChannel(channel_idx, channel)) { int i = 0; out_frame[i++] = RESP_CODE_CHANNEL_INFO; out_frame[i++] = channel_idx; @@ -1588,64 +1499,52 @@ void MyMesh::handleCmdFrame(size_t len) i += 16; // NOTE: only 128-bit supported _serial->writeFrame(out_frame, i); } - else - { + else { writeErrFrame(ERR_CODE_NOT_FOUND); } } - else if (cmd_frame[0] == CMD_SET_CHANNEL && len >= 2 + 32 + 32) - { + else if (cmd_frame[0] == CMD_SET_CHANNEL && len >= 2 + 32 + 32) { writeErrFrame(ERR_CODE_UNSUPPORTED_CMD); // not supported (yet) } - else if (cmd_frame[0] == CMD_SET_CHANNEL && len >= 2 + 32 + 16) - { + else if (cmd_frame[0] == CMD_SET_CHANNEL && len >= 2 + 32 + 16) { uint8_t channel_idx = cmd_frame[1]; ChannelDetails channel; StrHelper::strncpy(channel.name, (char *)&cmd_frame[2], 32); memset(channel.channel.secret, 0, sizeof(channel.channel.secret)); memcpy(channel.channel.secret, &cmd_frame[2 + 32], 16); // NOTE: only 128-bit supported - if (setChannel(channel_idx, channel)) - { + if (setChannel(channel_idx, channel)) { saveChannels(); writeOKFrame(); } - else - { + else { writeErrFrame(ERR_CODE_NOT_FOUND); // bad channel_idx } } - else if (cmd_frame[0] == CMD_SIGN_START) - { + else if (cmd_frame[0] == CMD_SIGN_START) { out_frame[0] = RESP_CODE_SIGN_START; out_frame[1] = 0; // reserved uint32_t len = MAX_SIGN_DATA_LEN; memcpy(&out_frame[2], &len, 4); _serial->writeFrame(out_frame, 6); - if (sign_data) - { + if (sign_data) { free(sign_data); } sign_data = (uint8_t *)malloc(MAX_SIGN_DATA_LEN); sign_data_len = 0; } - else if (cmd_frame[0] == CMD_SIGN_DATA && len > 1) - { - if (sign_data == NULL || sign_data_len + (len - 1) > MAX_SIGN_DATA_LEN) - { + else if (cmd_frame[0] == CMD_SIGN_DATA && len > 1) { + if (sign_data == NULL || sign_data_len + (len - 1) > MAX_SIGN_DATA_LEN) { writeErrFrame(sign_data == NULL ? ERR_CODE_BAD_STATE : ERR_CODE_TABLE_FULL); // error: too long } - else - { + else { memcpy(&sign_data[sign_data_len], &cmd_frame[1], len - 1); sign_data_len += (len - 1); writeOKFrame(); } } - else if (cmd_frame[0] == CMD_SIGN_FINISH) - { - if (sign_data) - { + else if (cmd_frame[0] == CMD_SIGN_FINISH) { + if (sign_data) { self_id.sign(&out_frame[1], sign_data, sign_data_len); free(sign_data); // don't need sign_data now @@ -1654,19 +1553,16 @@ void MyMesh::handleCmdFrame(size_t len) out_frame[0] = RESP_CODE_SIGNATURE; _serial->writeFrame(out_frame, 1 + SIGNATURE_SIZE); } - else - { + else { writeErrFrame(ERR_CODE_BAD_STATE); } } - else if (cmd_frame[0] == CMD_SEND_TRACE_PATH && len > 10 && len - 10 < MAX_PATH_SIZE) - { + else if (cmd_frame[0] == CMD_SEND_TRACE_PATH && len > 10 && len - 10 < MAX_PATH_SIZE) { uint32_t tag, auth; memcpy(&tag, &cmd_frame[1], 4); memcpy(&auth, &cmd_frame[5], 4); auto pkt = createTrace(tag, auth, cmd_frame[9]); - if (pkt) - { + if (pkt) { uint8_t path_len = len - 10; sendDirect(pkt, &cmd_frame[10], path_len); @@ -1679,38 +1575,31 @@ void MyMesh::handleCmdFrame(size_t len) memcpy(&out_frame[6], &est_timeout, 4); _serial->writeFrame(out_frame, 10); } - else - { + else { writeErrFrame(ERR_CODE_TABLE_FULL); } } - else if (cmd_frame[0] == CMD_SET_DEVICE_PIN && len >= 5) - { + else if (cmd_frame[0] == CMD_SET_DEVICE_PIN && len >= 5) { // get pin from command frame uint32_t pin; memcpy(&pin, &cmd_frame[1], 4); // ensure pin is zero, or a valid 6 digit pin - if (pin == 0 || (pin >= 100000 && pin <= 999999)) - { + if (pin == 0 || (pin >= 100000 && pin <= 999999)) { _prefs.ble_pin = pin; savePrefs(); writeOKFrame(); } - else - { + else { writeErrFrame(ERR_CODE_ILLEGAL_ARG); } } - else if (cmd_frame[0] == CMD_GET_CUSTOM_VARS) - { + else if (cmd_frame[0] == CMD_GET_CUSTOM_VARS) { out_frame[0] = RESP_CODE_CUSTOM_VARS; char *dp = (char *)&out_frame[1]; - for (int i = 0; i < sensors.getNumSettings() && dp - (char *)&out_frame[1] < 140; i++) - { - if (i > 0) - { + for (int i = 0; i < sensors.getNumSettings() && dp - (char *)&out_frame[1] < 140; i++) { + if (i > 0) { *dp++ = ','; } strcpy(dp, sensors.getSettingName(i)); @@ -1721,31 +1610,25 @@ void MyMesh::handleCmdFrame(size_t len) } _serial->writeFrame(out_frame, dp - (char *)out_frame); } - else if (cmd_frame[0] == CMD_SET_CUSTOM_VAR && len >= 4) - { + else if (cmd_frame[0] == CMD_SET_CUSTOM_VAR && len >= 4) { cmd_frame[len] = 0; char *sp = (char *)&cmd_frame[1]; char *np = strchr(sp, ':'); // look for separator char - if (np) - { + if (np) { *np++ = 0; // modify 'cmd_frame', replace ':' with null bool success = sensors.setSettingValue(sp, np); - if (success) - { + if (success) { writeOKFrame(); } - else - { + else { writeErrFrame(ERR_CODE_ILLEGAL_ARG); } } - else - { + else { writeErrFrame(ERR_CODE_ILLEGAL_ARG); } } - else - { + else { writeErrFrame(ERR_CODE_UNSUPPORTED_CMD); MESH_DEBUG_PRINTLN("ERROR: unknown command: %02X", cmd_frame[0]); } @@ -1756,42 +1639,35 @@ void MyMesh::loop() BaseChatMesh::loop(); size_t len = _serial->checkRecvFrame(cmd_frame); - if (len > 0) - { + if (len > 0) { handleCmdFrame(len); } else if (_iter_started // check if our ContactsIterator is 'running' && !_serial->isWriteBusy() // don't spam the Serial Interface too quickly! - ) - { + ) { ContactInfo contact; - if (_iter.hasNext(this, contact)) - { - if (contact.lastmod > _iter_filter_since) - { // apply the 'since' filter + if (_iter.hasNext(this, contact)) { + if (contact.lastmod > _iter_filter_since) { // apply the 'since' filter writeContactRespFrame(RESP_CODE_CONTACT, contact); - if (contact.lastmod > _most_recent_lastmod) - { + if (contact.lastmod > _most_recent_lastmod) { _most_recent_lastmod = contact.lastmod; // save for the RESP_CODE_END_OF_CONTACTS frame } } } - else - { // EOF + else { // EOF out_frame[0] = RESP_CODE_END_OF_CONTACTS; - memcpy(&out_frame[1], &_most_recent_lastmod, 4); // include the most recent lastmod, so app can update their 'since' + memcpy(&out_frame[1], &_most_recent_lastmod, + 4); // include the most recent lastmod, so app can update their 'since' _serial->writeFrame(out_frame, 5); _iter_started = false; } } - else if (!_serial->isWriteBusy()) - { + else if (!_serial->isWriteBusy()) { checkConnections(); } // is there are pending dirty contacts write needed? - if (dirty_contacts_expiry && millisHasNowPassed(dirty_contacts_expiry)) - { + if (dirty_contacts_expiry && millisHasNowPassed(dirty_contacts_expiry)) { saveContacts(); dirty_contacts_expiry = 0; } @@ -1805,14 +1681,12 @@ void MyMesh::loop() bool MyMesh::advert() { auto pkt = createSelfAdvert(_prefs.node_name, sensors.node_lat, sensors.node_lon); - if (pkt) - { + if (pkt) { sendZeroHop(pkt); writeOKFrame(); return true; } - else - { + else { writeErrFrame(ERR_CODE_TABLE_FULL); return false; } diff --git a/examples/companion_radio/MyMesh.h b/examples/companion_radio/MyMesh.h index a4794f1f1..574b9878f 100644 --- a/examples/companion_radio/MyMesh.h +++ b/examples/companion_radio/MyMesh.h @@ -1,21 +1,20 @@ -#ifndef MYMESH_H -#define MYMESH_H +#pragma once #include #include #ifdef DISPLAY_CLASS - #include "UITask.h" +#include "UITask.h" #endif /*------------ Frame Protocol --------------*/ -#define FIRMWARE_VER_CODE 5 +#define FIRMWARE_VER_CODE 5 #ifndef FIRMWARE_BUILD_DATE - #define FIRMWARE_BUILD_DATE "24 May 2025" +#define FIRMWARE_BUILD_DATE "24 May 2025" #endif #ifndef FIRMWARE_VERSION - #define FIRMWARE_VERSION "v1.6.2" +#define FIRMWARE_VERSION "v1.6.2" #endif #if defined(NRF52_PLATFORM) || defined(STM32_PLATFORM) @@ -26,258 +25,197 @@ #include #endif -#include -#include -#include -#include -#include #include "NodePrefs.h" + #include +#include +#include +#include +#include +#include #include /* ---------------------------------- CONFIGURATION ------------------------------------- */ #ifndef LORA_FREQ - #define LORA_FREQ 915.0 +#define LORA_FREQ 915.0 #endif #ifndef LORA_BW - #define LORA_BW 250 +#define LORA_BW 250 #endif #ifndef LORA_SF - #define LORA_SF 10 +#define LORA_SF 10 #endif #ifndef LORA_CR - #define LORA_CR 5 +#define LORA_CR 5 #endif #ifndef LORA_TX_POWER - #define LORA_TX_POWER 20 +#define LORA_TX_POWER 20 #endif #ifndef MAX_LORA_TX_POWER - #define MAX_LORA_TX_POWER LORA_TX_POWER +#define MAX_LORA_TX_POWER LORA_TX_POWER #endif #ifndef MAX_CONTACTS - #define MAX_CONTACTS 100 +#define MAX_CONTACTS 100 #endif #ifndef OFFLINE_QUEUE_SIZE - #define OFFLINE_QUEUE_SIZE 16 +#define OFFLINE_QUEUE_SIZE 16 #endif #ifndef BLE_NAME_PREFIX - #define BLE_NAME_PREFIX "MeshCore-" +#define BLE_NAME_PREFIX "MeshCore-" #endif #include -#define SEND_TIMEOUT_BASE_MILLIS 500 -#define FLOOD_SEND_TIMEOUT_FACTOR 16.0f -#define DIRECT_SEND_PERHOP_FACTOR 6.0f -#define DIRECT_SEND_PERHOP_EXTRA_MILLIS 250 -#define LAZY_CONTACTS_WRITE_DELAY 5000 - -#define PUBLIC_GROUP_PSK "izOH6cXN6mrJ5e26oRXNcg==" - -#define CMD_APP_START 1 -#define CMD_SEND_TXT_MSG 2 -#define CMD_SEND_CHANNEL_TXT_MSG 3 -#define CMD_GET_CONTACTS 4 // with optional 'since' (for efficient sync) -#define CMD_GET_DEVICE_TIME 5 -#define CMD_SET_DEVICE_TIME 6 -#define CMD_SEND_SELF_ADVERT 7 -#define CMD_SET_ADVERT_NAME 8 -#define CMD_ADD_UPDATE_CONTACT 9 -#define CMD_SYNC_NEXT_MESSAGE 10 -#define CMD_SET_RADIO_PARAMS 11 -#define CMD_SET_RADIO_TX_POWER 12 -#define CMD_RESET_PATH 13 -#define CMD_SET_ADVERT_LATLON 14 -#define CMD_REMOVE_CONTACT 15 -#define CMD_SHARE_CONTACT 16 -#define CMD_EXPORT_CONTACT 17 -#define CMD_IMPORT_CONTACT 18 -#define CMD_REBOOT 19 -#define CMD_GET_BATTERY_VOLTAGE 20 -#define CMD_SET_TUNING_PARAMS 21 -#define CMD_DEVICE_QEURY 22 -#define CMD_EXPORT_PRIVATE_KEY 23 -#define CMD_IMPORT_PRIVATE_KEY 24 -#define CMD_SEND_RAW_DATA 25 -#define CMD_SEND_LOGIN 26 -#define CMD_SEND_STATUS_REQ 27 -#define CMD_HAS_CONNECTION 28 -#define CMD_LOGOUT 29 // 'Disconnect' -#define CMD_GET_CONTACT_BY_KEY 30 -#define CMD_GET_CHANNEL 31 -#define CMD_SET_CHANNEL 32 -#define CMD_SIGN_START 33 -#define CMD_SIGN_DATA 34 -#define CMD_SIGN_FINISH 35 -#define CMD_SEND_TRACE_PATH 36 -#define CMD_SET_DEVICE_PIN 37 -#define CMD_SET_OTHER_PARAMS 38 -#define CMD_SEND_TELEMETRY_REQ 39 -#define CMD_GET_CUSTOM_VARS 40 -#define CMD_SET_CUSTOM_VAR 41 - -#define RESP_CODE_OK 0 -#define RESP_CODE_ERR 1 -#define RESP_CODE_CONTACTS_START 2 // first reply to CMD_GET_CONTACTS -#define RESP_CODE_CONTACT 3 // multiple of these (after CMD_GET_CONTACTS) -#define RESP_CODE_END_OF_CONTACTS 4 // last reply to CMD_GET_CONTACTS -#define RESP_CODE_SELF_INFO 5 // reply to CMD_APP_START -#define RESP_CODE_SENT 6 // reply to CMD_SEND_TXT_MSG -#define RESP_CODE_CONTACT_MSG_RECV 7 // a reply to CMD_SYNC_NEXT_MESSAGE (ver < 3) -#define RESP_CODE_CHANNEL_MSG_RECV 8 // a reply to CMD_SYNC_NEXT_MESSAGE (ver < 3) -#define RESP_CODE_CURR_TIME 9 // a reply to CMD_GET_DEVICE_TIME -#define RESP_CODE_NO_MORE_MESSAGES 10 // a reply to CMD_SYNC_NEXT_MESSAGE -#define RESP_CODE_EXPORT_CONTACT 11 -#define RESP_CODE_BATTERY_VOLTAGE 12 // a reply to a CMD_GET_BATTERY_VOLTAGE -#define RESP_CODE_DEVICE_INFO 13 // a reply to CMD_DEVICE_QEURY -#define RESP_CODE_PRIVATE_KEY 14 // a reply to CMD_EXPORT_PRIVATE_KEY -#define RESP_CODE_DISABLED 15 -#define RESP_CODE_CONTACT_MSG_RECV_V3 16 // a reply to CMD_SYNC_NEXT_MESSAGE (ver >= 3) -#define RESP_CODE_CHANNEL_MSG_RECV_V3 17 // a reply to CMD_SYNC_NEXT_MESSAGE (ver >= 3) -#define RESP_CODE_CHANNEL_INFO 18 // a reply to CMD_GET_CHANNEL -#define RESP_CODE_SIGN_START 19 -#define RESP_CODE_SIGNATURE 20 -#define RESP_CODE_CUSTOM_VARS 21 +#define SEND_TIMEOUT_BASE_MILLIS 500 +#define FLOOD_SEND_TIMEOUT_FACTOR 16.0f +#define DIRECT_SEND_PERHOP_FACTOR 6.0f +#define DIRECT_SEND_PERHOP_EXTRA_MILLIS 250 +#define LAZY_CONTACTS_WRITE_DELAY 5000 + +#define PUBLIC_GROUP_PSK "izOH6cXN6mrJ5e26oRXNcg==" // these are _pushed_ to client app at any time -#define PUSH_CODE_ADVERT 0x80 -#define PUSH_CODE_PATH_UPDATED 0x81 -#define PUSH_CODE_SEND_CONFIRMED 0x82 -#define PUSH_CODE_MSG_WAITING 0x83 -#define PUSH_CODE_RAW_DATA 0x84 -#define PUSH_CODE_LOGIN_SUCCESS 0x85 -#define PUSH_CODE_LOGIN_FAIL 0x86 -#define PUSH_CODE_STATUS_RESPONSE 0x87 -#define PUSH_CODE_LOG_RX_DATA 0x88 -#define PUSH_CODE_TRACE_DATA 0x89 -#define PUSH_CODE_NEW_ADVERT 0x8A -#define PUSH_CODE_TELEMETRY_RESPONSE 0x8B - -#define ERR_CODE_UNSUPPORTED_CMD 1 -#define ERR_CODE_NOT_FOUND 2 -#define ERR_CODE_TABLE_FULL 3 -#define ERR_CODE_BAD_STATE 4 -#define ERR_CODE_FILE_IO_ERROR 5 -#define ERR_CODE_ILLEGAL_ARG 6 +#define PUSH_CODE_ADVERT 0x80 +#define PUSH_CODE_PATH_UPDATED 0x81 +#define PUSH_CODE_SEND_CONFIRMED 0x82 +#define PUSH_CODE_MSG_WAITING 0x83 +#define PUSH_CODE_RAW_DATA 0x84 +#define PUSH_CODE_LOGIN_SUCCESS 0x85 +#define PUSH_CODE_LOGIN_FAIL 0x86 +#define PUSH_CODE_STATUS_RESPONSE 0x87 +#define PUSH_CODE_LOG_RX_DATA 0x88 +#define PUSH_CODE_TRACE_DATA 0x89 +#define PUSH_CODE_NEW_ADVERT 0x8A +#define PUSH_CODE_TELEMETRY_RESPONSE 0x8B + +#define ERR_CODE_UNSUPPORTED_CMD 1 +#define ERR_CODE_NOT_FOUND 2 +#define ERR_CODE_TABLE_FULL 3 +#define ERR_CODE_BAD_STATE 4 +#define ERR_CODE_FILE_IO_ERROR 5 +#define ERR_CODE_ILLEGAL_ARG 6 /* -------------------------------------------------------------------------------------- */ -#define REQ_TYPE_GET_STATUS 0x01 // same as _GET_STATS -#define REQ_TYPE_KEEP_ALIVE 0x02 -#define REQ_TYPE_GET_TELEMETRY_DATA 0x03 +#define REQ_TYPE_GET_STATUS 0x01 // same as _GET_STATS +#define REQ_TYPE_KEEP_ALIVE 0x02 +#define REQ_TYPE_GET_TELEMETRY_DATA 0x03 -#define MAX_SIGN_DATA_LEN (8*1024) // 8K +#define MAX_SIGN_DATA_LEN (8 * 1024) // 8K class MyMesh : public BaseChatMesh { public: - MyMesh(mesh::Radio& radio, mesh::RNG& rng, mesh::RTCClock& rtc, SimpleMeshTables& tables); - - void begin(FILESYSTEM& fs, bool has_display); - void startInterface(BaseSerialInterface& serial); - void loadPrefsInt(const char* filename); - void savePrefs(); - - const char* getNodeName(); - NodePrefs* getNodePrefs(); - uint32_t getBLEPin(); - - void loop(); - void handleCmdFrame(size_t len); - bool advert(); + MyMesh(mesh::Radio &radio, mesh::RNG &rng, mesh::RTCClock &rtc, SimpleMeshTables &tables); + + void begin(FILESYSTEM &fs, bool has_display); + void startInterface(BaseSerialInterface &serial); + void loadPrefsInt(const char *filename); + void savePrefs(); + + const char *getNodeName(); + NodePrefs *getNodePrefs(); + uint32_t getBLEPin(); + + void loop(); + void handleCmdFrame(size_t len); + bool advert(); protected: - float getAirtimeBudgetFactor() const override; - int getInterferenceThreshold() const override; - int calcRxDelay(float score, uint32_t air_time) const override; - - void logRxRaw(float snr, float rssi, const uint8_t raw[], int len) override; - bool isAutoAddEnabled() const override; - void onDiscoveredContact(ContactInfo& contact, bool is_new) override; - void onContactPathUpdated(const ContactInfo& contact) override; - bool processAck(const uint8_t *data) override; - void queueMessage(const ContactInfo& from, uint8_t txt_type, mesh::Packet* pkt, - uint32_t sender_timestamp, const uint8_t* extra, int extra_len, const char *text); - - void onMessageRecv(const ContactInfo& from, mesh::Packet* pkt, uint32_t sender_timestamp, const char *text) override; - void onCommandDataRecv(const ContactInfo& from, mesh::Packet* pkt, uint32_t sender_timestamp, const char *text) override; - void onSignedMessageRecv(const ContactInfo& from, mesh::Packet* pkt, uint32_t sender_timestamp, - const uint8_t *sender_prefix, const char *text) override; - void onChannelMessageRecv(const mesh::GroupChannel& channel, mesh::Packet* pkt, uint32_t timestamp, const char *text) override; - - uint8_t onContactRequest(const ContactInfo& contact, uint32_t sender_timestamp, const uint8_t* data, uint8_t len, uint8_t* reply) override; - void onContactResponse(const ContactInfo& contact, const uint8_t* data, uint8_t len) override; - void onRawDataRecv(mesh::Packet* packet) override; - void onTraceRecv(mesh::Packet* packet, uint32_t tag, uint32_t auth_code, uint8_t flags, const uint8_t* path_snrs, - const uint8_t* path_hashes, uint8_t path_len) override; - - uint32_t calcFloodTimeoutMillisFor(uint32_t pkt_airtime_millis) const override; - uint32_t calcDirectTimeoutMillisFor(uint32_t pkt_airtime_millis, uint8_t path_len) const override; - void onSendTimeout() override; + float getAirtimeBudgetFactor() const override; + int getInterferenceThreshold() const override; + int calcRxDelay(float score, uint32_t air_time) const override; + + void logRxRaw(float snr, float rssi, const uint8_t raw[], int len) override; + bool isAutoAddEnabled() const override; + void onDiscoveredContact(ContactInfo &contact, bool is_new) override; + void onContactPathUpdated(const ContactInfo &contact) override; + bool processAck(const uint8_t *data) override; + void queueMessage(const ContactInfo &from, uint8_t txt_type, mesh::Packet *pkt, uint32_t sender_timestamp, + const uint8_t *extra, int extra_len, const char *text); + + void onMessageRecv(const ContactInfo &from, mesh::Packet *pkt, uint32_t sender_timestamp, + const char *text) override; + void onCommandDataRecv(const ContactInfo &from, mesh::Packet *pkt, uint32_t sender_timestamp, + const char *text) override; + void onSignedMessageRecv(const ContactInfo &from, mesh::Packet *pkt, uint32_t sender_timestamp, + const uint8_t *sender_prefix, const char *text) override; + void onChannelMessageRecv(const mesh::GroupChannel &channel, mesh::Packet *pkt, uint32_t timestamp, + const char *text) override; + + uint8_t onContactRequest(const ContactInfo &contact, uint32_t sender_timestamp, const uint8_t *data, + uint8_t len, uint8_t *reply) override; + void onContactResponse(const ContactInfo &contact, const uint8_t *data, uint8_t len) override; + void onRawDataRecv(mesh::Packet *packet) override; + void onTraceRecv(mesh::Packet *packet, uint32_t tag, uint32_t auth_code, uint8_t flags, + const uint8_t *path_snrs, const uint8_t *path_hashes, uint8_t path_len) override; + + uint32_t calcFloodTimeoutMillisFor(uint32_t pkt_airtime_millis) const override; + uint32_t calcDirectTimeoutMillisFor(uint32_t pkt_airtime_millis, uint8_t path_len) const override; + void onSendTimeout() override; private: - void writeOKFrame(); - void writeErrFrame(uint8_t err_code); - void writeDisabledFrame(); - void writeContactRespFrame(uint8_t code, const ContactInfo& contact); - void updateContactFromFrame(ContactInfo& contact, const uint8_t* frame, int len); - void addToOfflineQueue(const uint8_t frame[], int len); - int getFromOfflineQueue(uint8_t frame[]); - void loadMainIdentity(); - bool saveMainIdentity(const mesh::LocalIdentity& identity); - void loadContacts(); - void saveContacts(); - void loadChannels(); - void saveChannels(); - int getBlobByKey(const uint8_t key[], int key_len, uint8_t dest_buf[]) override; - bool putBlobByKey(const uint8_t key[], int key_len, const uint8_t src_buf[], int len) override; + void writeOKFrame(); + void writeErrFrame(uint8_t err_code); + void writeDisabledFrame(); + void writeContactRespFrame(uint8_t code, const ContactInfo &contact); + void updateContactFromFrame(ContactInfo &contact, const uint8_t *frame, int len); + void addToOfflineQueue(const uint8_t frame[], int len); + int getFromOfflineQueue(uint8_t frame[]); + void loadMainIdentity(); + bool saveMainIdentity(const mesh::LocalIdentity &identity); + void loadContacts(); + void saveContacts(); + void loadChannels(); + void saveChannels(); + int getBlobByKey(const uint8_t key[], int key_len, uint8_t dest_buf[]) override; + bool putBlobByKey(const uint8_t key[], int key_len, const uint8_t src_buf[], int len) override; private: - FILESYSTEM* _fs; - IdentityStore* _identity_store; - NodePrefs _prefs; - uint32_t pending_login; - uint32_t pending_status; - uint32_t pending_telemetry; - BaseSerialInterface* _serial; - - ContactsIterator _iter; - uint32_t _iter_filter_since; - uint32_t _most_recent_lastmod; - uint32_t _active_ble_pin; - bool _iter_started; - uint8_t app_target_ver; - uint8_t* sign_data; - uint32_t sign_data_len; - unsigned long dirty_contacts_expiry; - - uint8_t cmd_frame[MAX_FRAME_SIZE + 1]; - uint8_t out_frame[MAX_FRAME_SIZE + 1]; - CayenneLPP telemetry; - - struct Frame { - uint8_t len; - uint8_t buf[MAX_FRAME_SIZE]; - }; - int offline_queue_len; - Frame offline_queue[OFFLINE_QUEUE_SIZE]; - - struct AckTableEntry { - unsigned long msg_sent; - uint32_t ack; - }; - #define EXPECTED_ACK_TABLE_SIZE 8 - AckTableEntry expected_ack_table[EXPECTED_ACK_TABLE_SIZE]; // circular table - int next_ack_idx; + FILESYSTEM *_fs; + IdentityStore *_identity_store; + NodePrefs _prefs; + uint32_t pending_login; + uint32_t pending_status; + uint32_t pending_telemetry; + BaseSerialInterface *_serial; + + ContactsIterator _iter; + uint32_t _iter_filter_since; + uint32_t _most_recent_lastmod; + uint32_t _active_ble_pin; + bool _iter_started; + uint8_t app_target_ver; + uint8_t *sign_data; + uint32_t sign_data_len; + unsigned long dirty_contacts_expiry; + + uint8_t cmd_frame[MAX_FRAME_SIZE + 1]; + uint8_t out_frame[MAX_FRAME_SIZE + 1]; + CayenneLPP telemetry; + + struct Frame { + uint8_t len; + uint8_t buf[MAX_FRAME_SIZE]; + }; + int offline_queue_len; + Frame offline_queue[OFFLINE_QUEUE_SIZE]; + + struct AckTableEntry { + unsigned long msg_sent; + uint32_t ack; + }; +#define EXPECTED_ACK_TABLE_SIZE 8 + AckTableEntry expected_ack_table[EXPECTED_ACK_TABLE_SIZE]; // circular table + int next_ack_idx; }; extern StdRNG fast_rng; extern SimpleMeshTables tables; extern MyMesh the_mesh; #ifdef DISPLAY_CLASS - extern UITask ui_task; -#endif -#endif // MYMESH_H \ No newline at end of file +extern UITask ui_task; +#endif \ No newline at end of file diff --git a/examples/companion_radio/NodePrefs.h b/examples/companion_radio/NodePrefs.h index 09d04266b..44d7ecbf2 100644 --- a/examples/companion_radio/NodePrefs.h +++ b/examples/companion_radio/NodePrefs.h @@ -1,13 +1,11 @@ -#ifndef NODE_PREFS_H -#define NODE_PREFS_H - +#pragma once #include // For uint8_t, uint32_t -#define TELEM_MODE_DENY 0 -#define TELEM_MODE_ALLOW_FLAGS 1 // use contact.flags -#define TELEM_MODE_ALLOW_ALL 2 +#define TELEM_MODE_DENY 0 +#define TELEM_MODE_ALLOW_FLAGS 1 // use contact.flags +#define TELEM_MODE_ALLOW_ALL 2 -struct NodePrefs { // persisted to file +struct NodePrefs { // persisted to file float airtime_factor; char node_name[32]; float freq; @@ -22,6 +20,4 @@ struct NodePrefs { // persisted to file uint8_t telemetry_mode_env; float rx_delay_base; uint32_t ble_pin; -}; - -#endif // NODE_PREFS_H \ No newline at end of file +}; \ No newline at end of file diff --git a/examples/companion_radio/UITask.h b/examples/companion_radio/UITask.h index 6d7e1eb34..f52c0961c 100644 --- a/examples/companion_radio/UITask.h +++ b/examples/companion_radio/UITask.h @@ -1,53 +1,43 @@ -#ifndef UI_TASK_H -#define UI_TASK_H - +#pragma once #include #include #include #ifdef PIN_BUZZER - #include +#include #endif -#include "NodePrefs.h" #include "Button.h" +#include "NodePrefs.h" - enum class UIEventType -{ - none, - contactMessage, - channelMessage, - roomMessage, - newContactMessage, - ack -}; +enum class UIEventType { none, contactMessage, channelMessage, roomMessage, newContactMessage, ack }; class UITask { - DisplayDriver* _display; - mesh::MainBoard* _board; + DisplayDriver *_display; + mesh::MainBoard *_board; #ifdef PIN_BUZZER genericBuzzer buzzer; #endif unsigned long _next_refresh, _auto_off; bool _connected; uint32_t _pin_code; - NodePrefs* _node_prefs; + NodePrefs *_node_prefs; char _version_info[32]; char _origin[62]; char _msg[80]; int _msgcount; bool _need_refresh = true; - bool _displayWasOn = false; // Track display state before button press + bool _displayWasOn = false; // Track display state before button press // Button handlers #if defined(PIN_USER_BTN) || defined(PIN_USER_BTN_ANA) - Button* _userButton = nullptr; + Button *_userButton = nullptr; #endif void renderCurrScreen(); void userLedHandler(); void renderBatteryIndicator(uint16_t batteryMilliVolts); - + // Button action handlers void handleButtonAnyPress(); void handleButtonShortPress(); @@ -55,22 +45,21 @@ class UITask { void handleButtonTriplePress(); void handleButtonLongPress(); - public: - - UITask(mesh::MainBoard* board) : _board(board), _display(NULL) { - _next_refresh = 0; - _connected = false; + UITask(mesh::MainBoard *board) : _board(board), _display(NULL) + { + _next_refresh = 0; + _connected = false; } - void begin(DisplayDriver* display, NodePrefs* node_prefs, const char* build_date, const char* firmware_version, uint32_t pin_code); + void begin(DisplayDriver *display, NodePrefs *node_prefs, const char *build_date, + const char *firmware_version, uint32_t pin_code); void setHasConnection(bool connected) { _connected = connected; } bool hasDisplay() const { return _display != NULL; } void clearMsgPreview(); void msgRead(int msgcount); - void newMsg(uint8_t path_len, const char* from_name, const char* text, int msgcount); + void newMsg(uint8_t path_len, const char *from_name, const char *text, int msgcount); void soundBuzzer(UIEventType bet = UIEventType::none); void shutdown(bool restart = false); void loop(); -}; -#endif //UI_TASK_H \ No newline at end of file +}; \ No newline at end of file From 73a7a96ae461301ba0419d4211ec82bb3249f75f Mon Sep 17 00:00:00 2001 From: Florent Date: Sat, 31 May 2025 20:29:03 +0200 Subject: [PATCH 06/19] wio_e5 : bme280 support --- variants/wio-e5-mini/platformio.ini | 2 ++ variants/wio-e5-mini/target.cpp | 34 ++++++++++++++++++++++------- variants/wio-e5-mini/target.h | 15 ++++++++++++- 3 files changed, 42 insertions(+), 9 deletions(-) diff --git a/variants/wio-e5-mini/platformio.ini b/variants/wio-e5-mini/platformio.ini index 55ab0bc8a..887304ea2 100644 --- a/variants/wio-e5-mini/platformio.ini +++ b/variants/wio-e5-mini/platformio.ini @@ -10,6 +10,8 @@ build_flags = ${stm32_base.build_flags} -I variants/wio-e5-mini build_src_filter = ${stm32_base.build_src_filter} +<../variants/wio-e5-mini> +lib_deps = ${stm32_base.lib_deps} + finitespace/BME280 @ ^3.0.0 [env:wio-e5-mini-repeater] extends = lora_e5_mini diff --git a/variants/wio-e5-mini/target.cpp b/variants/wio-e5-mini/target.cpp index 8ccbe384f..7a2b0d394 100644 --- a/variants/wio-e5-mini/target.cpp +++ b/variants/wio-e5-mini/target.cpp @@ -18,20 +18,15 @@ static const Module::RfSwitchMode_t rfswitch_table[] = { }; VolatileRTCClock rtc_clock; -SensorManager sensors; +BME280I2C bme; +WIOE5SensorManager sensors(bme); #ifndef LORA_CR #define LORA_CR 5 #endif bool radio_init() { -// rtc_clock.begin(Wire); - -// #ifdef SX126X_DIO3_TCXO_VOLTAGE -// float tcxo = SX126X_DIO3_TCXO_VOLTAGE; -// #else -// float tcxo = 1.6f; -// #endif + Wire.begin(); radio.setRfSwitchTable(rfswitch_pins, rfswitch_table); @@ -71,3 +66,26 @@ mesh::LocalIdentity radio_new_identity() { RadioNoiseListener rng(radio); return mesh::LocalIdentity(&rng); // create new random identity } + +bool WIOE5SensorManager::querySensors(uint8_t requester_permissions, CayenneLPP& telemetry) { + if (!has_bme) return false; + + float temp(NAN), hum(NAN), pres(NAN); + + BME280::TempUnit tempUnit(BME280::TempUnit_Celsius); + BME280::PresUnit presUnit(BME280::PresUnit_bar); + + _bme->read(pres, temp, hum, tempUnit, presUnit); + + telemetry.addTemperature(TELEM_CHANNEL_SELF, temp); + telemetry.addRelativeHumidity(TELEM_CHANNEL_SELF, hum); + telemetry.addBarometricPressure(TELEM_CHANNEL_SELF, pres); + + return true; +} + +bool WIOE5SensorManager::begin() { + has_bme = _bme->begin(); + + return has_bme; +} \ No newline at end of file diff --git a/variants/wio-e5-mini/target.h b/variants/wio-e5-mini/target.h index f7a882eef..daf7e1745 100644 --- a/variants/wio-e5-mini/target.h +++ b/variants/wio-e5-mini/target.h @@ -8,6 +8,9 @@ #include #include +#include +#include + class WIOE5Board : public STM32Board { public: const char* getManufacturerName() const override { @@ -21,10 +24,20 @@ class WIOE5Board : public STM32Board { } }; +class WIOE5SensorManager : public SensorManager { + BME280I2C* _bme; + bool has_bme = false; + +public: + WIOE5SensorManager(BME280I2C& bme) : _bme(&bme) {} + bool begin() override; + bool querySensors(uint8_t requester_permissions, CayenneLPP& telemetry) override; +}; + extern WIOE5Board board; extern WRAPPER_CLASS radio_driver; extern VolatileRTCClock rtc_clock; -extern SensorManager sensors; +extern WIOE5SensorManager sensors; bool radio_init(); uint32_t radio_get_rng_seed(); From 92c296308a96b79c0e4199d1e9d126e37949c72f Mon Sep 17 00:00:00 2001 From: Florent Date: Sun, 1 Jun 2025 08:30:53 +0200 Subject: [PATCH 07/19] wioe5: integrate sensor in sensor mgr --- src/helpers/stm32/InternalFileSystem.cpp | 7 +++++-- variants/wio-e5-mini/target.cpp | 9 ++++----- variants/wio-e5-mini/target.h | 4 ++-- 3 files changed, 11 insertions(+), 9 deletions(-) diff --git a/src/helpers/stm32/InternalFileSystem.cpp b/src/helpers/stm32/InternalFileSystem.cpp index 2714ec6b1..dc032eb96 100644 --- a/src/helpers/stm32/InternalFileSystem.cpp +++ b/src/helpers/stm32/InternalFileSystem.cpp @@ -126,11 +126,14 @@ InternalFileSystem::InternalFileSystem(void) bool InternalFileSystem::begin(void) { + volatile bool format_fs; #ifdef FORMAT_FS - this->format(); + format_fs = true; + #else + format_fs = false; // you can always use debugger to force formatting ;) #endif // failed to mount, erase all sector then format and mount again - if ( !Adafruit_LittleFS::begin() ) + if ( format_fs || !Adafruit_LittleFS::begin() ) { // lfs format this->format(); diff --git a/variants/wio-e5-mini/target.cpp b/variants/wio-e5-mini/target.cpp index 7a2b0d394..e3dd2ec76 100644 --- a/variants/wio-e5-mini/target.cpp +++ b/variants/wio-e5-mini/target.cpp @@ -18,8 +18,7 @@ static const Module::RfSwitchMode_t rfswitch_table[] = { }; VolatileRTCClock rtc_clock; -BME280I2C bme; -WIOE5SensorManager sensors(bme); +WIOE5SensorManager sensors; #ifndef LORA_CR #define LORA_CR 5 @@ -73,9 +72,9 @@ bool WIOE5SensorManager::querySensors(uint8_t requester_permissions, CayenneLPP& float temp(NAN), hum(NAN), pres(NAN); BME280::TempUnit tempUnit(BME280::TempUnit_Celsius); - BME280::PresUnit presUnit(BME280::PresUnit_bar); + BME280::PresUnit presUnit(BME280::PresUnit_hPa); - _bme->read(pres, temp, hum, tempUnit, presUnit); + bme.read(pres, temp, hum, tempUnit, presUnit); telemetry.addTemperature(TELEM_CHANNEL_SELF, temp); telemetry.addRelativeHumidity(TELEM_CHANNEL_SELF, hum); @@ -85,7 +84,7 @@ bool WIOE5SensorManager::querySensors(uint8_t requester_permissions, CayenneLPP& } bool WIOE5SensorManager::begin() { - has_bme = _bme->begin(); + has_bme = bme.begin(); return has_bme; } \ No newline at end of file diff --git a/variants/wio-e5-mini/target.h b/variants/wio-e5-mini/target.h index daf7e1745..4b510d56a 100644 --- a/variants/wio-e5-mini/target.h +++ b/variants/wio-e5-mini/target.h @@ -25,11 +25,11 @@ class WIOE5Board : public STM32Board { }; class WIOE5SensorManager : public SensorManager { - BME280I2C* _bme; + BME280I2C bme; bool has_bme = false; public: - WIOE5SensorManager(BME280I2C& bme) : _bme(&bme) {} + WIOE5SensorManager() {} bool begin() override; bool querySensors(uint8_t requester_permissions, CayenneLPP& telemetry) override; }; From 31cbf9ed0e5af4ac70e5a59ea93f79319a685c12 Mon Sep 17 00:00:00 2001 From: Florent Date: Sat, 31 May 2025 10:57:22 +0200 Subject: [PATCH 08/19] gps : sync time on fix --- examples/companion_radio/main.cpp | 2 +- src/helpers/sensors/LocationProvider.h | 6 ++++ .../sensors/MicroNMEALocationProvider.h | 29 +++++++++++++++++-- variants/t1000-e/target.cpp | 21 ++++++++++++-- 4 files changed, 52 insertions(+), 6 deletions(-) diff --git a/examples/companion_radio/main.cpp b/examples/companion_radio/main.cpp index 6677d49b5..8c822a5c3 100644 --- a/examples/companion_radio/main.cpp +++ b/examples/companion_radio/main.cpp @@ -74,7 +74,7 @@ static uint32_t _atoi(const char* sp) { /* GLOBAL OBJECTS */ StdRNG fast_rng; SimpleMeshTables tables; -MyMesh the_mesh(radio_driver, fast_rng, *new VolatileRTCClock(), tables); // TODO: test with 'rtc_clock' in target.cpp +MyMesh the_mesh(radio_driver, fast_rng, rtc_clock, tables); #ifdef DISPLAY_CLASS #include "UITask.h" diff --git a/src/helpers/sensors/LocationProvider.h b/src/helpers/sensors/LocationProvider.h index 056e61e08..f51eea281 100644 --- a/src/helpers/sensors/LocationProvider.h +++ b/src/helpers/sensors/LocationProvider.h @@ -4,13 +4,19 @@ class LocationProvider { +protected: + bool _time_sync_needed = true; public: + virtual void syncTime() { _time_sync_needed = true; } + virtual bool waitingTimeSync() { return _time_sync_needed; } virtual long getLatitude() = 0; virtual long getLongitude() = 0; virtual long getAltitude() = 0; + virtual long satellitesCount() = 0; virtual bool isValid() = 0; virtual long getTimestamp() = 0; + virtual void sendSentence(const char * sentence); virtual void reset(); virtual void begin(); virtual void stop(); diff --git a/src/helpers/sensors/MicroNMEALocationProvider.h b/src/helpers/sensors/MicroNMEALocationProvider.h index 9f439e259..ee6e43ebf 100644 --- a/src/helpers/sensors/MicroNMEALocationProvider.h +++ b/src/helpers/sensors/MicroNMEALocationProvider.h @@ -19,13 +19,16 @@ class MicroNMEALocationProvider : public LocationProvider { char _nmeaBuffer[100]; MicroNMEA nmea; + mesh::RTCClock* _clock; Stream* _gps_serial; int _pin_reset; int _pin_en; + long next_check = 0; + long time_valid = 0; public : - MicroNMEALocationProvider(Stream& ser, int pin_reset = GPS_RESET, int pin_en = GPS_EN) : - _gps_serial(&ser), nmea(_nmeaBuffer, sizeof(_nmeaBuffer)), _pin_reset(pin_reset), _pin_en(pin_en) { + MicroNMEALocationProvider(Stream& ser, mesh::RTCClock* clock = &rtc_clock, int pin_reset = GPS_RESET, int pin_en = GPS_EN) : + _gps_serial(&ser), nmea(_nmeaBuffer, sizeof(_nmeaBuffer)), _pin_reset(pin_reset), _pin_en(pin_en), _clock(clock) { if (_pin_reset != -1) { pinMode(_pin_reset, OUTPUT); digitalWrite(_pin_reset, GPS_RESET_FORCE); @@ -59,6 +62,7 @@ public : } } + void syncTime() override { nmea.clear(); LocationProvider::syncTime(); } long getLatitude() override { return nmea.getLatitude(); } long getLongitude() override { return nmea.getLongitude(); } long getAltitude() override { @@ -66,6 +70,7 @@ public : nmea.getAltitude(alt); return alt; } + long satellitesCount() override { return nmea.getNumSatellites(); } bool isValid() override { return nmea.isValid(); } long getTimestamp() override { @@ -73,7 +78,12 @@ public : return dt.unixtime(); } + void sendSentence(const char *sentence) override { + nmea.sendSentence(*_gps_serial, sentence); + } + void loop() override { + while (_gps_serial->available()) { char c = _gps_serial->read(); #ifdef GPS_NMEA_DEBUG @@ -81,5 +91,20 @@ public : #endif nmea.process(c); } + + if (!isValid()) time_valid = 0; + + if (millis() > next_check) { + next_check = millis() + 1000; + if (_time_sync_needed && time_valid > 2) { + if (_clock != NULL) { + rtc_clock.setCurrentTime(getTimestamp()); + _time_sync_needed = false; + } + } + if (isValid()) { + time_valid ++; + } + } } }; \ No newline at end of file diff --git a/variants/t1000-e/target.cpp b/variants/t1000-e/target.cpp index be82ca763..296551e16 100644 --- a/variants/t1000-e/target.cpp +++ b/variants/t1000-e/target.cpp @@ -9,7 +9,7 @@ RADIO_CLASS radio = new Module(P_LORA_NSS, P_LORA_DIO_1, P_LORA_RESET, P_LORA_BU WRAPPER_CLASS radio_driver(radio, board); VolatileRTCClock rtc_clock; -MicroNMEALocationProvider nmea = MicroNMEALocationProvider(Serial1); +MicroNMEALocationProvider nmea = MicroNMEALocationProvider(Serial1, &rtc_clock); T1000SensorManager sensors = T1000SensorManager(nmea); #ifdef DISPLAY_CLASS @@ -179,14 +179,26 @@ void T1000SensorManager::loop() { } } -int T1000SensorManager::getNumSettings() const { return 1; } // just one supported: "gps" (power switch) +int T1000SensorManager::getNumSettings() const { return 2; } // just one supported: "gps" (power switch) const char* T1000SensorManager::getSettingName(int i) const { - return i == 0 ? "gps" : NULL; + switch (i) { + case 0: + return "gps"; + break; + case 1: + return "sync"; + break; + default: + return NULL; + break; + } } const char* T1000SensorManager::getSettingValue(int i) const { if (i == 0) { return gps_active ? "1" : "0"; + } else if (i == 1) { + return _nmea->waitingTimeSync() ? "1" : "0"; } return NULL; } @@ -198,6 +210,9 @@ bool T1000SensorManager::setSettingValue(const char* name, const char* value) { start_gps(); } return true; + } else if (strcmp(name, "sync") == 0) { + _nmea->syncTime(); // whatever the value ... + return true; } return false; // not supported } From 49da6957b5ea18f449f2e389f8c3476c2fdfd426 Mon Sep 17 00:00:00 2001 From: Florent Date: Sun, 1 Jun 2025 14:12:22 +0200 Subject: [PATCH 09/19] micronmea: was using global rtc_clock to sync instead of _clock --- src/helpers/sensors/MicroNMEALocationProvider.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/helpers/sensors/MicroNMEALocationProvider.h b/src/helpers/sensors/MicroNMEALocationProvider.h index ee6e43ebf..a4a2f5d61 100644 --- a/src/helpers/sensors/MicroNMEALocationProvider.h +++ b/src/helpers/sensors/MicroNMEALocationProvider.h @@ -98,7 +98,7 @@ public : next_check = millis() + 1000; if (_time_sync_needed && time_valid > 2) { if (_clock != NULL) { - rtc_clock.setCurrentTime(getTimestamp()); + _clock.setCurrentTime(getTimestamp()); _time_sync_needed = false; } } From 14cd4ea0104b4be5f0b1a48ba822193bd603f2e8 Mon Sep 17 00:00:00 2001 From: Florent Date: Sun, 1 Jun 2025 15:32:02 +0200 Subject: [PATCH 10/19] t1000: remove sync custom var --- .../sensors/MicroNMEALocationProvider.h | 2 +- variants/t1000-e/target.cpp | 19 ++----------------- 2 files changed, 3 insertions(+), 18 deletions(-) diff --git a/src/helpers/sensors/MicroNMEALocationProvider.h b/src/helpers/sensors/MicroNMEALocationProvider.h index a4a2f5d61..e8b09d9a8 100644 --- a/src/helpers/sensors/MicroNMEALocationProvider.h +++ b/src/helpers/sensors/MicroNMEALocationProvider.h @@ -98,7 +98,7 @@ public : next_check = millis() + 1000; if (_time_sync_needed && time_valid > 2) { if (_clock != NULL) { - _clock.setCurrentTime(getTimestamp()); + _clock->setCurrentTime(getTimestamp()); _time_sync_needed = false; } } diff --git a/variants/t1000-e/target.cpp b/variants/t1000-e/target.cpp index 296551e16..29ca1acd4 100644 --- a/variants/t1000-e/target.cpp +++ b/variants/t1000-e/target.cpp @@ -179,26 +179,14 @@ void T1000SensorManager::loop() { } } -int T1000SensorManager::getNumSettings() const { return 2; } // just one supported: "gps" (power switch) +int T1000SensorManager::getNumSettings() const { return 1; } // just one supported: "gps" (power switch) const char* T1000SensorManager::getSettingName(int i) const { - switch (i) { - case 0: - return "gps"; - break; - case 1: - return "sync"; - break; - default: - return NULL; - break; - } + return i == 0 ? "gps" : NULL; } const char* T1000SensorManager::getSettingValue(int i) const { if (i == 0) { return gps_active ? "1" : "0"; - } else if (i == 1) { - return _nmea->waitingTimeSync() ? "1" : "0"; } return NULL; } @@ -210,9 +198,6 @@ bool T1000SensorManager::setSettingValue(const char* name, const char* value) { start_gps(); } return true; - } else if (strcmp(name, "sync") == 0) { - _nmea->syncTime(); // whatever the value ... - return true; } return false; // not supported } From 3749264e073a8440a2cf28376f5132915baa3c49 Mon Sep 17 00:00:00 2001 From: Scott Powell Date: Sun, 1 Jun 2025 23:55:57 +1000 Subject: [PATCH 11/19] * MicroNMEALocationProvider: clock param now NULL by default --- src/helpers/sensors/MicroNMEALocationProvider.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/helpers/sensors/MicroNMEALocationProvider.h b/src/helpers/sensors/MicroNMEALocationProvider.h index e8b09d9a8..5a2c59d3c 100644 --- a/src/helpers/sensors/MicroNMEALocationProvider.h +++ b/src/helpers/sensors/MicroNMEALocationProvider.h @@ -27,7 +27,7 @@ class MicroNMEALocationProvider : public LocationProvider { long time_valid = 0; public : - MicroNMEALocationProvider(Stream& ser, mesh::RTCClock* clock = &rtc_clock, int pin_reset = GPS_RESET, int pin_en = GPS_EN) : + MicroNMEALocationProvider(Stream& ser, mesh::RTCClock* clock = NULL, int pin_reset = GPS_RESET, int pin_en = GPS_EN) : _gps_serial(&ser), nmea(_nmeaBuffer, sizeof(_nmeaBuffer)), _pin_reset(pin_reset), _pin_en(pin_en), _clock(clock) { if (_pin_reset != -1) { pinMode(_pin_reset, OUTPUT); From 42efbda40a8c7ef334b7745b661066e3f1baae69 Mon Sep 17 00:00:00 2001 From: hank Date: Sun, 1 Jun 2025 19:57:35 -0700 Subject: [PATCH 12/19] Re-applying ecd2b0b --- examples/companion_radio/MyMesh.cpp | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/examples/companion_radio/MyMesh.cpp b/examples/companion_radio/MyMesh.cpp index db40169f9..f4ee900b2 100644 --- a/examples/companion_radio/MyMesh.cpp +++ b/examples/companion_radio/MyMesh.cpp @@ -545,7 +545,8 @@ void MyMesh::onChannelMessageRecv(const mesh::GroupChannel &channel, mesh::Packe out_frame[i++] = RESP_CODE_CHANNEL_MSG_RECV; } - out_frame[i++] = findChannelIdx(channel); + uint8_t channel_idx = findChannelIdx(channel); + out_frame[i++] = channel_idx; uint8_t path_len = out_frame[i++] = pkt->isRouteFlood() ? pkt->path_len : 0xFF; out_frame[i++] = TXT_TYPE_PLAIN; @@ -570,7 +571,13 @@ void MyMesh::onChannelMessageRecv(const mesh::GroupChannel &channel, mesh::Packe #endif } #ifdef DISPLAY_CLASS - ui_task.newMsg(path_len, "Public", text, offline_queue_len); + // Get the channel name from the channel index + const char *channel_name = "Unknown"; + ChannelDetails channel_details; + if (getChannel(channel_idx, channel_details)) { + channel_name = channel_details.name; + } + ui_task.newMsg(path_len, channel_name, text, offline_queue_len); #endif } From 40bf7bbb9f4536c947d3589914013b81f0979565 Mon Sep 17 00:00:00 2001 From: hank Date: Sun, 1 Jun 2025 20:15:16 -0700 Subject: [PATCH 13/19] Reverting changes to Button code --- examples/companion_radio/Button.cpp | 225 +++++++++++++--------------- examples/companion_radio/Button.h | 112 +++++++------- 2 files changed, 166 insertions(+), 171 deletions(-) diff --git a/examples/companion_radio/Button.cpp b/examples/companion_radio/Button.cpp index 5de4b7024..ec1f0f69b 100644 --- a/examples/companion_radio/Button.cpp +++ b/examples/companion_radio/Button.cpp @@ -1,142 +1,125 @@ #include "Button.h" -Button::Button(uint8_t pin, bool activeState) - : _pin(pin), _activeState(activeState), _isAnalog(false), _analogThreshold(20) -{ - _currentState = false; // Initialize as not pressed - _lastState = _currentState; +Button::Button(uint8_t pin, bool activeState) + : _pin(pin), _activeState(activeState), _isAnalog(false), _analogThreshold(20) { + _currentState = false; // Initialize as not pressed + _lastState = _currentState; } Button::Button(uint8_t pin, bool activeState, bool isAnalog, uint16_t analogThreshold) - : _pin(pin), _activeState(activeState), _isAnalog(isAnalog), _analogThreshold(analogThreshold) -{ - _currentState = false; // Initialize as not pressed - _lastState = _currentState; + : _pin(pin), _activeState(activeState), _isAnalog(isAnalog), _analogThreshold(analogThreshold) { + _currentState = false; // Initialize as not pressed + _lastState = _currentState; } -void Button::begin() -{ - _currentState = readButton(); - _lastState = _currentState; +void Button::begin() { + _currentState = readButton(); + _lastState = _currentState; } -void Button::update() -{ - uint32_t now = millis(); - - // Read button at specified interval - if (now - _lastReadTime < BUTTON_READ_INTERVAL_MS) { - return; - } - _lastReadTime = now; - - bool newState = readButton(); - - // Check if state has changed - if (newState != _lastState) { - _stateChangeTime = now; - } - - // Debounce check - if ((now - _stateChangeTime) > BUTTON_DEBOUNCE_TIME_MS) { - if (newState != _currentState) { - _currentState = newState; - handleStateChange(); +void Button::update() { + uint32_t now = millis(); + + // Read button at specified interval + if (now - _lastReadTime < BUTTON_READ_INTERVAL_MS) { + return; } - } - - _lastState = newState; - - // Handle multi-click timeout - if (_state == WAITING_FOR_MULTI_CLICK && (now - _releaseTime) > BUTTON_CLICK_TIMEOUT_MS) { - // Timeout reached, process the clicks - if (_clickCount == 1) { - triggerEvent(SHORT_PRESS); + _lastReadTime = now; + + bool newState = readButton(); + + // Check if state has changed + if (newState != _lastState) { + _stateChangeTime = now; } - else if (_clickCount == 2) { - triggerEvent(DOUBLE_PRESS); + + // Debounce check + if ((now - _stateChangeTime) > BUTTON_DEBOUNCE_TIME_MS) { + if (newState != _currentState) { + _currentState = newState; + handleStateChange(); + } } - else if (_clickCount >= 3) { - triggerEvent(TRIPLE_PRESS); + + _lastState = newState; + + // Handle multi-click timeout + if (_state == WAITING_FOR_MULTI_CLICK && (now - _releaseTime) > BUTTON_CLICK_TIMEOUT_MS) { + // Timeout reached, process the clicks + if (_clickCount == 1) { + triggerEvent(SHORT_PRESS); + } else if (_clickCount == 2) { + triggerEvent(DOUBLE_PRESS); + } else if (_clickCount >= 3) { + triggerEvent(TRIPLE_PRESS); + } + _clickCount = 0; + _state = IDLE; + } + + // Handle long press while button is held + if (_state == PRESSED && (now - _pressTime) > BUTTON_LONG_PRESS_TIME_MS) { + triggerEvent(LONG_PRESS); + _state = IDLE; // Prevent multiple press events + _clickCount = 0; } - _clickCount = 0; - _state = IDLE; - } - - // Handle long press while button is held - if (_state == PRESSED && (now - _pressTime) > BUTTON_LONG_PRESS_TIME_MS) { - triggerEvent(LONG_PRESS); - _state = IDLE; // Prevent multiple press events - _clickCount = 0; - } } -bool Button::readButton() -{ - if (_isAnalog) { - return (analogRead(_pin) < _analogThreshold); - } - else { - return (digitalRead(_pin) == _activeState); - } +bool Button::readButton() { + if (_isAnalog) { + return (analogRead(_pin) < _analogThreshold); + } else { + return (digitalRead(_pin) == _activeState); + } } -void Button::handleStateChange() -{ - uint32_t now = millis(); - - if (_currentState) { - // Button pressed - _pressTime = now; - _state = PRESSED; - triggerEvent(ANY_PRESS); - } - else { - // Button released - if (_state == PRESSED) { - uint32_t pressDuration = now - _pressTime; - - if (pressDuration < BUTTON_LONG_PRESS_TIME_MS) { - // Short press detected - _clickCount++; - _releaseTime = now; - _state = WAITING_FOR_MULTI_CLICK; - } - else { - // Long press already handled in update() - _state = IDLE; - _clickCount = 0; - } +void Button::handleStateChange() { + uint32_t now = millis(); + + if (_currentState) { + // Button pressed + _pressTime = now; + _state = PRESSED; + triggerEvent(ANY_PRESS); + } else { + // Button released + if (_state == PRESSED) { + uint32_t pressDuration = now - _pressTime; + + if (pressDuration < BUTTON_LONG_PRESS_TIME_MS) { + // Short press detected + _clickCount++; + _releaseTime = now; + _state = WAITING_FOR_MULTI_CLICK; + } else { + // Long press already handled in update() + _state = IDLE; + _clickCount = 0; + } + } } - } } -void Button::triggerEvent(EventType event) -{ - _lastEvent = event; - - switch (event) { - case ANY_PRESS: - if (_onAnyPress) - _onAnyPress(); - break; - case SHORT_PRESS: - if (_onShortPress) - _onShortPress(); - break; - case DOUBLE_PRESS: - if (_onDoublePress) - _onDoublePress(); - break; - case TRIPLE_PRESS: - if (_onTriplePress) - _onTriplePress(); - break; - case LONG_PRESS: - if (_onLongPress) - _onLongPress(); - break; - default: - break; - } +void Button::triggerEvent(EventType event) { + _lastEvent = event; + + switch (event) { + case ANY_PRESS: + if (_onAnyPress) _onAnyPress(); + break; + case SHORT_PRESS: + if (_onShortPress) _onShortPress(); + break; + case DOUBLE_PRESS: + if (_onDoublePress) _onDoublePress(); + break; + case TRIPLE_PRESS: + if (_onTriplePress) _onTriplePress(); + break; + case LONG_PRESS: + if (_onLongPress) _onLongPress(); + break; + default: + break; + } } \ No newline at end of file diff --git a/examples/companion_radio/Button.h b/examples/companion_radio/Button.h index 855645938..47c792bd7 100644 --- a/examples/companion_radio/Button.h +++ b/examples/companion_radio/Button.h @@ -4,62 +4,74 @@ #include // Button timing configuration -#define BUTTON_DEBOUNCE_TIME_MS 50 // Debounce time in ms -#define BUTTON_CLICK_TIMEOUT_MS 500 // Max time between clicks for multi-click -#define BUTTON_LONG_PRESS_TIME_MS 3000 // Time to trigger long press (3 seconds) -#define BUTTON_READ_INTERVAL_MS 10 // How often to read the button +#define BUTTON_DEBOUNCE_TIME_MS 50 // Debounce time in ms +#define BUTTON_CLICK_TIMEOUT_MS 500 // Max time between clicks for multi-click +#define BUTTON_LONG_PRESS_TIME_MS 3000 // Time to trigger long press (3 seconds) +#define BUTTON_READ_INTERVAL_MS 10 // How often to read the button class Button { public: - enum EventType { NONE, SHORT_PRESS, DOUBLE_PRESS, TRIPLE_PRESS, LONG_PRESS, ANY_PRESS }; + enum EventType { + NONE, + SHORT_PRESS, + DOUBLE_PRESS, + TRIPLE_PRESS, + LONG_PRESS, + ANY_PRESS + }; - using EventCallback = std::function; + using EventCallback = std::function; - Button(uint8_t pin, bool activeState = LOW); - Button(uint8_t pin, bool activeState, bool isAnalog, uint16_t analogThreshold = 20); - - void begin(); - void update(); - - // Set callbacks for different events - void onShortPress(EventCallback callback) { _onShortPress = callback; } - void onDoublePress(EventCallback callback) { _onDoublePress = callback; } - void onTriplePress(EventCallback callback) { _onTriplePress = callback; } - void onLongPress(EventCallback callback) { _onLongPress = callback; } - void onAnyPress(EventCallback callback) { _onAnyPress = callback; } - - // State getters - bool isPressed() const { return _currentState; } - EventType getLastEvent() const { return _lastEvent; } + Button(uint8_t pin, bool activeState = LOW); + Button(uint8_t pin, bool activeState, bool isAnalog, uint16_t analogThreshold = 20); + + void begin(); + void update(); + + // Set callbacks for different events + void onShortPress(EventCallback callback) { _onShortPress = callback; } + void onDoublePress(EventCallback callback) { _onDoublePress = callback; } + void onTriplePress(EventCallback callback) { _onTriplePress = callback; } + void onLongPress(EventCallback callback) { _onLongPress = callback; } + void onAnyPress(EventCallback callback) { _onAnyPress = callback; } + + // State getters + bool isPressed() const { return _currentState; } + EventType getLastEvent() const { return _lastEvent; } private: - enum State { IDLE, PRESSED, RELEASED, WAITING_FOR_MULTI_CLICK }; - - uint8_t _pin; - bool _activeState; - bool _isAnalog; - uint16_t _analogThreshold; - - State _state = IDLE; - bool _currentState; - bool _lastState; - - uint32_t _stateChangeTime = 0; - uint32_t _pressTime = 0; - uint32_t _releaseTime = 0; - uint32_t _lastReadTime = 0; - - uint8_t _clickCount = 0; - EventType _lastEvent = NONE; - - // Callbacks - EventCallback _onShortPress = nullptr; - EventCallback _onDoublePress = nullptr; - EventCallback _onTriplePress = nullptr; - EventCallback _onLongPress = nullptr; - EventCallback _onAnyPress = nullptr; + enum State { + IDLE, + PRESSED, + RELEASED, + WAITING_FOR_MULTI_CLICK + }; - bool readButton(); - void handleStateChange(); - void triggerEvent(EventType event); + uint8_t _pin; + bool _activeState; + bool _isAnalog; + uint16_t _analogThreshold; + + State _state = IDLE; + bool _currentState; + bool _lastState; + + uint32_t _stateChangeTime = 0; + uint32_t _pressTime = 0; + uint32_t _releaseTime = 0; + uint32_t _lastReadTime = 0; + + uint8_t _clickCount = 0; + EventType _lastEvent = NONE; + + // Callbacks + EventCallback _onShortPress = nullptr; + EventCallback _onDoublePress = nullptr; + EventCallback _onTriplePress = nullptr; + EventCallback _onLongPress = nullptr; + EventCallback _onAnyPress = nullptr; + + bool readButton(); + void handleStateChange(); + void triggerEvent(EventType event); }; \ No newline at end of file From 9247ce460a52008943b39f25d3565fdec05384ca Mon Sep 17 00:00:00 2001 From: hank Date: Sun, 1 Jun 2025 20:16:29 -0700 Subject: [PATCH 14/19] Reverting changes to simple_secure_chat main --- examples/simple_secure_chat/main.cpp | 424 +++++++++++---------------- 1 file changed, 173 insertions(+), 251 deletions(-) diff --git a/examples/simple_secure_chat/main.cpp b/examples/simple_secure_chat/main.cpp index 2440b6976..63ff20da3 100644 --- a/examples/simple_secure_chat/main.cpp +++ b/examples/simple_secure_chat/main.cpp @@ -1,57 +1,56 @@ -#include // needed for PlatformIO +#include // needed for PlatformIO #include #if defined(NRF52_PLATFORM) -#include + #include #elif defined(RP2040_PLATFORM) -#include + #include #elif defined(ESP32) -#include + #include #endif -#include #include -#include -#include #include +#include +#include +#include #include /* ---------------------------------- CONFIGURATION ------------------------------------- */ -#define FIRMWARE_VER_TEXT "v2 (build: 4 Feb 2025)" +#define FIRMWARE_VER_TEXT "v2 (build: 4 Feb 2025)" #ifndef LORA_FREQ -#define LORA_FREQ 915.0 + #define LORA_FREQ 915.0 #endif #ifndef LORA_BW -#define LORA_BW 250 + #define LORA_BW 250 #endif #ifndef LORA_SF -#define LORA_SF 10 + #define LORA_SF 10 #endif #ifndef LORA_CR -#define LORA_CR 5 + #define LORA_CR 5 #endif #ifndef LORA_TX_POWER -#define LORA_TX_POWER 20 + #define LORA_TX_POWER 20 #endif #ifndef MAX_CONTACTS -#define MAX_CONTACTS 100 + #define MAX_CONTACTS 100 #endif #include -#define SEND_TIMEOUT_BASE_MILLIS 500 -#define FLOOD_SEND_TIMEOUT_FACTOR 16.0f -#define DIRECT_SEND_PERHOP_FACTOR 6.0f -#define DIRECT_SEND_PERHOP_EXTRA_MILLIS 250 +#define SEND_TIMEOUT_BASE_MILLIS 500 +#define FLOOD_SEND_TIMEOUT_FACTOR 16.0f +#define DIRECT_SEND_PERHOP_FACTOR 6.0f +#define DIRECT_SEND_PERHOP_EXTRA_MILLIS 250 -#define PUBLIC_GROUP_PSK "izOH6cXN6mrJ5e26oRXNcg==" +#define PUBLIC_GROUP_PSK "izOH6cXN6mrJ5e26oRXNcg==" // Believe it or not, this std C function is busted on some platforms! -static uint32_t _atoi(const char *sp) -{ +static uint32_t _atoi(const char* sp) { uint32_t n = 0; while (*sp && *sp >= '0' && *sp <= '9') { n *= 10; @@ -62,7 +61,7 @@ static uint32_t _atoi(const char *sp) /* -------------------------------------------------------------------------------------- */ -struct NodePrefs { // persisted to file +struct NodePrefs { // persisted to file float airtime_factor; char node_name[32]; double node_lat, node_lon; @@ -72,35 +71,30 @@ struct NodePrefs { // persisted to file }; class MyMesh : public BaseChatMesh, ContactVisitor { - FILESYSTEM *_fs; + FILESYSTEM* _fs; NodePrefs _prefs; uint32_t expected_ack_crc; - ChannelDetails *_public; + ChannelDetails* _public; unsigned long last_msg_sent; - ContactInfo *curr_recipient; - char command[512 + 10]; + ContactInfo* curr_recipient; + char command[512+10]; uint8_t tmp_buf[256]; char hex_buf[512]; - const char *getTypeName(uint8_t type) const - { - if (type == ADV_TYPE_CHAT) - return "Chat"; - if (type == ADV_TYPE_REPEATER) - return "Repeater"; - if (type == ADV_TYPE_ROOM) - return "Room"; - return "??"; // unknown + const char* getTypeName(uint8_t type) const { + if (type == ADV_TYPE_CHAT) return "Chat"; + if (type == ADV_TYPE_REPEATER) return "Repeater"; + if (type == ADV_TYPE_ROOM) return "Room"; + return "??"; // unknown } - void loadContacts() - { + void loadContacts() { if (_fs->exists("/contacts")) { -#if defined(RP2040_PLATFORM) + #if defined(RP2040_PLATFORM) File file = _fs->open("/contacts", "r"); -#else + #else File file = _fs->open("/contacts"); -#endif + #endif if (file) { bool full = false; while (!full) { @@ -110,31 +104,28 @@ class MyMesh : public BaseChatMesh, ContactVisitor { uint32_t reserved; bool success = (file.read(pub_key, 32) == 32); - success = success && (file.read((uint8_t *)&c.name, 32) == 32); + success = success && (file.read((uint8_t *) &c.name, 32) == 32); success = success && (file.read(&c.type, 1) == 1); success = success && (file.read(&c.flags, 1) == 1); success = success && (file.read(&unused, 1) == 1); - success = success && (file.read((uint8_t *)&reserved, 4) == 4); - success = success && (file.read((uint8_t *)&c.out_path_len, 1) == 1); - success = success && (file.read((uint8_t *)&c.last_advert_timestamp, 4) == 4); + success = success && (file.read((uint8_t *) &reserved, 4) == 4); + success = success && (file.read((uint8_t *) &c.out_path_len, 1) == 1); + success = success && (file.read((uint8_t *) &c.last_advert_timestamp, 4) == 4); success = success && (file.read(c.out_path, 64) == 64); - c.gps_lat = c.gps_lon = 0; // not yet supported + c.gps_lat = c.gps_lon = 0; // not yet supported - if (!success) - break; // EOF + if (!success) break; // EOF c.id = mesh::Identity(pub_key); c.lastmod = 0; - if (!addContact(c)) - full = true; + if (!addContact(c)) full = true; } file.close(); } } } - void saveContacts() - { + void saveContacts() { #if defined(NRF52_PLATFORM) _fs->remove("/contacts"); File file = _fs->open("/contacts", FILE_O_WRITE); @@ -151,50 +142,44 @@ class MyMesh : public BaseChatMesh, ContactVisitor { while (iter.hasNext(this, c)) { bool success = (file.write(c.id.pub_key, 32) == 32); - success = success && (file.write((uint8_t *)&c.name, 32) == 32); + success = success && (file.write((uint8_t *) &c.name, 32) == 32); success = success && (file.write(&c.type, 1) == 1); success = success && (file.write(&c.flags, 1) == 1); success = success && (file.write(&unused, 1) == 1); - success = success && (file.write((uint8_t *)&reserved, 4) == 4); - success = success && (file.write((uint8_t *)&c.out_path_len, 1) == 1); - success = success && (file.write((uint8_t *)&c.last_advert_timestamp, 4) == 4); + success = success && (file.write((uint8_t *) &reserved, 4) == 4); + success = success && (file.write((uint8_t *) &c.out_path_len, 1) == 1); + success = success && (file.write((uint8_t *) &c.last_advert_timestamp, 4) == 4); success = success && (file.write(c.out_path, 64) == 64); - if (!success) - break; // write failed + if (!success) break; // write failed } file.close(); } } - void setClock(uint32_t timestamp) - { + void setClock(uint32_t timestamp) { uint32_t curr = getRTCClock()->getCurrentTime(); if (timestamp > curr) { getRTCClock()->setCurrentTime(timestamp); Serial.println(" (OK - clock set!)"); - } - else { + } else { Serial.println(" (ERR: clock cannot go backwards)"); } } - void importCard(const char *command) - { - while (*command == ' ') - command++; // skip leading spaces + void importCard(const char* command) { + while (*command == ' ') command++; // skip leading spaces if (memcmp(command, "meshcore://", 11) == 0) { - command += 11; // skip the prefix - char *ep = strchr(command, 0); // find end of string + command += 11; // skip the prefix + char *ep = strchr(command, 0); // find end of string while (ep > command) { ep--; - if (mesh::Utils::isHexChar(*ep)) - break; // found tail end of card - *ep = 0; // remove trailing spaces and other junk + if (mesh::Utils::isHexChar(*ep)) break; // found tail end of card + *ep = 0; // remove trailing spaces and other junk } int len = strlen(command); if (len % 2 == 0) { - len >>= 1; // halve, for num bytes + len >>= 1; // halve, for num bytes if (mesh::Utils::fromHex(tmp_buf, len, command)) { importContact(tmp_buf, len); return; @@ -205,112 +190,97 @@ class MyMesh : public BaseChatMesh, ContactVisitor { } protected: - float getAirtimeBudgetFactor() const override { return _prefs.airtime_factor; } + float getAirtimeBudgetFactor() const override { + return _prefs.airtime_factor; + } - int calcRxDelay(float score, uint32_t air_time) const override - { - return 0; // disable rxdelay + int calcRxDelay(float score, uint32_t air_time) const override { + return 0; // disable rxdelay } - bool allowPacketForward(const mesh::Packet *packet) override { return true; } + bool allowPacketForward(const mesh::Packet* packet) override { + return true; + } - void onDiscoveredContact(ContactInfo &contact, bool is_new) override - { + void onDiscoveredContact(ContactInfo& contact, bool is_new) override { // TODO: if not in favs, prompt to add as fav(?) Serial.printf("ADVERT from -> %s\n", contact.name); Serial.printf(" type: %s\n", getTypeName(contact.type)); - Serial.print(" public key: "); - mesh::Utils::printHex(Serial, contact.id.pub_key, PUB_KEY_SIZE); - Serial.println(); + Serial.print(" public key: "); mesh::Utils::printHex(Serial, contact.id.pub_key, PUB_KEY_SIZE); Serial.println(); saveContacts(); } - void onContactPathUpdated(const ContactInfo &contact) override - { - Serial.printf("PATH to: %s, path_len=%d\n", contact.name, (int32_t)contact.out_path_len); + void onContactPathUpdated(const ContactInfo& contact) override { + Serial.printf("PATH to: %s, path_len=%d\n", contact.name, (int32_t) contact.out_path_len); saveContacts(); } - bool processAck(const uint8_t *data) override - { - if (memcmp(data, &expected_ack_crc, 4) == 0) { // got an ACK from recipient + bool processAck(const uint8_t *data) override { + if (memcmp(data, &expected_ack_crc, 4) == 0) { // got an ACK from recipient Serial.printf(" Got ACK! (round trip: %d millis)\n", _ms->getMillis() - last_msg_sent); // NOTE: the same ACK can be received multiple times! - expected_ack_crc = 0; // reset our expected hash, now that we have received ACK + expected_ack_crc = 0; // reset our expected hash, now that we have received ACK return true; } - // uint32_t crc; - // memcpy(&crc, data, 4); - // MESH_DEBUG_PRINTLN("unknown ACK received: %08X (expected: %08X)", crc, expected_ack_crc); + //uint32_t crc; + //memcpy(&crc, data, 4); + //MESH_DEBUG_PRINTLN("unknown ACK received: %08X (expected: %08X)", crc, expected_ack_crc); return false; } - void onMessageRecv(const ContactInfo &from, mesh::Packet *pkt, uint32_t sender_timestamp, - const char *text) override - { + void onMessageRecv(const ContactInfo& from, mesh::Packet* pkt, uint32_t sender_timestamp, const char *text) override { Serial.printf("(%s) MSG -> from %s\n", pkt->isRouteDirect() ? "DIRECT" : "FLOOD", from.name); Serial.printf(" %s\n", text); - if (strcmp(text, "clock sync") == 0) { // special text command + if (strcmp(text, "clock sync") == 0) { // special text command setClock(sender_timestamp + 1); } } - void onCommandDataRecv(const ContactInfo &from, mesh::Packet *pkt, uint32_t sender_timestamp, - const char *text) override - { + void onCommandDataRecv(const ContactInfo& from, mesh::Packet* pkt, uint32_t sender_timestamp, const char *text) override { } - void onSignedMessageRecv(const ContactInfo &from, mesh::Packet *pkt, uint32_t sender_timestamp, - const uint8_t *sender_prefix, const char *text) override - { + void onSignedMessageRecv(const ContactInfo& from, mesh::Packet* pkt, uint32_t sender_timestamp, const uint8_t *sender_prefix, const char *text) override { } - void onChannelMessageRecv(const mesh::GroupChannel &channel, mesh::Packet *pkt, uint32_t timestamp, - const char *text) override - { + void onChannelMessageRecv(const mesh::GroupChannel& channel, mesh::Packet* pkt, uint32_t timestamp, const char *text) override { if (pkt->isRouteDirect()) { Serial.printf("PUBLIC CHANNEL MSG -> (Direct!)\n"); - } - else { + } else { Serial.printf("PUBLIC CHANNEL MSG -> (Flood) hops %d\n", pkt->path_len); } Serial.printf(" %s\n", text); } - uint8_t onContactRequest(const ContactInfo &contact, uint32_t sender_timestamp, const uint8_t *data, - uint8_t len, uint8_t *reply) override - { - return 0; // unknown + uint8_t onContactRequest(const ContactInfo& contact, uint32_t sender_timestamp, const uint8_t* data, uint8_t len, uint8_t* reply) override { + return 0; // unknown } - void onContactResponse(const ContactInfo &contact, const uint8_t *data, uint8_t len) override - { + void onContactResponse(const ContactInfo& contact, const uint8_t* data, uint8_t len) override { // not supported } - uint32_t calcFloodTimeoutMillisFor(uint32_t pkt_airtime_millis) const override - { + uint32_t calcFloodTimeoutMillisFor(uint32_t pkt_airtime_millis) const override { return SEND_TIMEOUT_BASE_MILLIS + (FLOOD_SEND_TIMEOUT_FACTOR * pkt_airtime_millis); } - uint32_t calcDirectTimeoutMillisFor(uint32_t pkt_airtime_millis, uint8_t path_len) const override - { - return SEND_TIMEOUT_BASE_MILLIS + - ((pkt_airtime_millis * DIRECT_SEND_PERHOP_FACTOR + DIRECT_SEND_PERHOP_EXTRA_MILLIS) * - (path_len + 1)); + uint32_t calcDirectTimeoutMillisFor(uint32_t pkt_airtime_millis, uint8_t path_len) const override { + return SEND_TIMEOUT_BASE_MILLIS + + ( (pkt_airtime_millis*DIRECT_SEND_PERHOP_FACTOR + DIRECT_SEND_PERHOP_EXTRA_MILLIS) * (path_len + 1)); } - void onSendTimeout() override { Serial.println(" ERROR: timed out, no ACK."); } + void onSendTimeout() override { + Serial.println(" ERROR: timed out, no ACK."); + } public: - MyMesh(mesh::Radio &radio, StdRNG &rng, mesh::RTCClock &rtc, SimpleMeshTables &tables) - : BaseChatMesh(radio, *new ArduinoMillis(), rng, rtc, *new StaticPoolPacketManager(16), tables) + MyMesh(mesh::Radio& radio, StdRNG& rng, mesh::RTCClock& rtc, SimpleMeshTables& tables) + : BaseChatMesh(radio, *new ArduinoMillis(), rng, rtc, *new StaticPoolPacketManager(16), tables) { // defaults memset(&_prefs, 0, sizeof(_prefs)); - _prefs.airtime_factor = 2.0; // one third + _prefs.airtime_factor = 2.0; // one third strcpy(_prefs.node_name, "NONAME"); _prefs.freq = LORA_FREQ; _prefs.tx_power_dbm = LORA_TX_POWER; @@ -322,49 +292,45 @@ class MyMesh : public BaseChatMesh, ContactVisitor { float getFreqPref() const { return _prefs.freq; } uint8_t getTxPowerPref() const { return _prefs.tx_power_dbm; } - void begin(FILESYSTEM &fs) - { + void begin(FILESYSTEM& fs) { _fs = &fs; BaseChatMesh::begin(); -#if defined(NRF52_PLATFORM) + #if defined(NRF52_PLATFORM) IdentityStore store(fs, ""); -#elif defined(RP2040_PLATFORM) + #elif defined(RP2040_PLATFORM) IdentityStore store(fs, "/identity"); store.begin(); -#else + #else IdentityStore store(fs, "/identity"); -#endif - if (!store.load("_main", self_id, _prefs.node_name, - sizeof(_prefs.node_name))) { // legacy: node_name was from identity file + #endif + if (!store.load("_main", self_id, _prefs.node_name, sizeof(_prefs.node_name))) { // legacy: node_name was from identity file // Need way to get some entropy to seed RNG Serial.println("Press ENTER to generate key:"); char c = 0; - while (c != '\n') { // wait for ENTER to be pressed - if (Serial.available()) - c = Serial.read(); + while (c != '\n') { // wait for ENTER to be pressed + if (Serial.available()) c = Serial.read(); } ((StdRNG *)getRNG())->begin(millis()); - self_id = mesh::LocalIdentity(getRNG()); // create new random identity + self_id = mesh::LocalIdentity(getRNG()); // create new random identity int count = 0; - while (count < 10 && (self_id.pub_key[0] == 0x00 || self_id.pub_key[0] == 0xFF)) { // reserved id hashes - self_id = mesh::LocalIdentity(getRNG()); - count++; + while (count < 10 && (self_id.pub_key[0] == 0x00 || self_id.pub_key[0] == 0xFF)) { // reserved id hashes + self_id = mesh::LocalIdentity(getRNG()); count++; } store.save("_main", self_id); } // load persisted prefs if (_fs->exists("/node_prefs")) { -#if defined(RP2040_PLATFORM) + #if defined(RP2040_PLATFORM) File file = _fs->open("/node_prefs", "r"); -#else + #else File file = _fs->open("/node_prefs"); -#endif + #endif if (file) { - file.read((uint8_t *)&_prefs, sizeof(_prefs)); + file.read((uint8_t *) &_prefs, sizeof(_prefs)); file.close(); } } @@ -373,8 +339,7 @@ class MyMesh : public BaseChatMesh, ContactVisitor { _public = addChannel("Public", PUBLIC_GROUP_PSK); // pre-configure Andy's public channel } - void savePrefs() - { + void savePrefs() { #if defined(NRF52_PLATFORM) _fs->remove("/node_prefs"); File file = _fs->open("/node_prefs", FILE_O_WRITE); @@ -389,8 +354,7 @@ class MyMesh : public BaseChatMesh, ContactVisitor { } } - void showWelcome() - { + void showWelcome() { Serial.println("===== MeshCore Chat Terminal ====="); Serial.println(); Serial.printf("WELCOME %s\n", _prefs.node_name); @@ -400,8 +364,7 @@ class MyMesh : public BaseChatMesh, ContactVisitor { Serial.println(); } - void sendSelfAdvert(int delay_millis) - { + void sendSelfAdvert(int delay_millis) { auto pkt = createSelfAdvert(_prefs.node_name, _prefs.node_lat, _prefs.node_lon); if (pkt) { sendFlood(pkt, delay_millis); @@ -409,8 +372,7 @@ class MyMesh : public BaseChatMesh, ContactVisitor { } // ContactVisitor - void onContactVisit(const ContactInfo &contact) override - { + void onContactVisit(const ContactInfo& contact) override { Serial.printf(" %s - ", contact.name); char tmp[40]; int32_t secs = contact.last_advert_timestamp - getRTCClock()->getCurrentTime(); @@ -418,159 +380,129 @@ class MyMesh : public BaseChatMesh, ContactVisitor { Serial.println(tmp); } - void handleCommand(const char *command) - { - while (*command == ' ') - command++; // skip leading spaces + void handleCommand(const char* command) { + while (*command == ' ') command++; // skip leading spaces if (memcmp(command, "send ", 5) == 0) { if (curr_recipient) { const char *text = &command[5]; uint32_t est_timeout; - int result = sendMessage(*curr_recipient, getRTCClock()->getCurrentTime(), 0, text, expected_ack_crc, - est_timeout); + int result = sendMessage(*curr_recipient, getRTCClock()->getCurrentTime(), 0, text, expected_ack_crc, est_timeout); if (result == MSG_SEND_FAILED) { Serial.println(" ERROR: unable to send."); - } - else { + } else { last_msg_sent = _ms->getMillis(); Serial.printf(" (message sent - %s)\n", result == MSG_SEND_SENT_FLOOD ? "FLOOD" : "DIRECT"); } - } - else { + } else { Serial.println(" ERROR: no recipient selected (use 'to' cmd)."); } - } - else if (memcmp(command, "public ", 7) == 0) { // send GroupChannel msg - uint8_t temp[5 + MAX_TEXT_LEN + 32]; + } else if (memcmp(command, "public ", 7) == 0) { // send GroupChannel msg + uint8_t temp[5+MAX_TEXT_LEN+32]; uint32_t timestamp = getRTCClock()->getCurrentTime(); - memcpy(temp, ×tamp, 4); // mostly an extra blob to help make packet_hash unique - temp[4] = 0; // attempt and flags + memcpy(temp, ×tamp, 4); // mostly an extra blob to help make packet_hash unique + temp[4] = 0; // attempt and flags - sprintf((char *)&temp[5], "%s: %s", _prefs.node_name, &command[7]); // : - temp[5 + MAX_TEXT_LEN] = 0; // truncate if too long + sprintf((char *) &temp[5], "%s: %s", _prefs.node_name, &command[7]); // : + temp[5 + MAX_TEXT_LEN] = 0; // truncate if too long - int len = strlen((char *)&temp[5]); + int len = strlen((char *) &temp[5]); auto pkt = createGroupDatagram(PAYLOAD_TYPE_GRP_TXT, _public->channel, temp, 5 + len); if (pkt) { sendFlood(pkt); Serial.println(" Sent."); - } - else { + } else { Serial.println(" ERROR: unable to send"); } - } - else if (memcmp(command, "list", 4) == 0) { // show Contact list, by most recent + } else if (memcmp(command, "list", 4) == 0) { // show Contact list, by most recent int n = 0; - if (command[4] == ' ') { // optional param, last 'N' + if (command[4] == ' ') { // optional param, last 'N' n = atoi(&command[5]); } scanRecentContacts(n, this); - } - else if (strcmp(command, "clock") == 0) { // show current time + } else if (strcmp(command, "clock") == 0) { // show current time uint32_t now = getRTCClock()->getCurrentTime(); DateTime dt = DateTime(now); - Serial.printf("%02d:%02d - %d/%d/%d UTC\n", dt.hour(), dt.minute(), dt.day(), dt.month(), dt.year()); - } - else if (memcmp(command, "time ", 5) == 0) { // set time (to epoch seconds) + Serial.printf( "%02d:%02d - %d/%d/%d UTC\n", dt.hour(), dt.minute(), dt.day(), dt.month(), dt.year()); + } else if (memcmp(command, "time ", 5) == 0) { // set time (to epoch seconds) uint32_t secs = _atoi(&command[5]); setClock(secs); - } - else if (memcmp(command, "to ", 3) == 0) { // set current recipient + } else if (memcmp(command, "to ", 3) == 0) { // set current recipient curr_recipient = searchContactsByPrefix(&command[3]); if (curr_recipient) { Serial.printf(" Recipient %s now selected.\n", curr_recipient->name); - } - else { + } else { Serial.println(" Error: Name prefix not found."); } - } - else if (strcmp(command, "to") == 0) { // show current recipient + } else if (strcmp(command, "to") == 0) { // show current recipient if (curr_recipient) { - Serial.printf(" Current: %s\n", curr_recipient->name); - } - else { - Serial.println(" Err: no recipient selected"); + Serial.printf(" Current: %s\n", curr_recipient->name); + } else { + Serial.println(" Err: no recipient selected"); } - } - else if (strcmp(command, "advert") == 0) { + } else if (strcmp(command, "advert") == 0) { auto pkt = createSelfAdvert(_prefs.node_name, _prefs.node_lat, _prefs.node_lon); if (pkt) { sendZeroHop(pkt); Serial.println(" (advert sent, zero hop)."); - } - else { + } else { Serial.println(" ERR: unable to send"); } - } - else if (strcmp(command, "reset path") == 0) { + } else if (strcmp(command, "reset path") == 0) { if (curr_recipient) { resetPathTo(*curr_recipient); saveContacts(); Serial.println(" Done."); } - } - else if (memcmp(command, "card", 4) == 0) { + } else if (memcmp(command, "card", 4) == 0) { Serial.printf("Hello %s\n", _prefs.node_name); auto pkt = createSelfAdvert(_prefs.node_name, _prefs.node_lat, _prefs.node_lon); if (pkt) { - uint8_t len = pkt->writeTo(tmp_buf); - releasePacket(pkt); // undo the obtainNewPacket() + uint8_t len = pkt->writeTo(tmp_buf); + releasePacket(pkt); // undo the obtainNewPacket() mesh::Utils::toHex(hex_buf, tmp_buf, len); Serial.println("Your MeshCore biz card:"); - Serial.print("meshcore://"); - Serial.println(hex_buf); + Serial.print("meshcore://"); Serial.println(hex_buf); Serial.println(); - } - else { + } else { Serial.println(" Error"); } - } - else if (memcmp(command, "import ", 7) == 0) { + } else if (memcmp(command, "import ", 7) == 0) { importCard(&command[7]); - } - else if (memcmp(command, "set ", 4) == 0) { - const char *config = &command[4]; + } else if (memcmp(command, "set ", 4) == 0) { + const char* config = &command[4]; if (memcmp(config, "af ", 3) == 0) { _prefs.airtime_factor = atof(&config[3]); savePrefs(); Serial.println(" OK"); - } - else if (memcmp(config, "name ", 5) == 0) { + } else if (memcmp(config, "name ", 5) == 0) { StrHelper::strncpy(_prefs.node_name, &config[5], sizeof(_prefs.node_name)); savePrefs(); Serial.println(" OK"); - } - else if (memcmp(config, "lat ", 4) == 0) { + } else if (memcmp(config, "lat ", 4) == 0) { _prefs.node_lat = atof(&config[4]); savePrefs(); Serial.println(" OK"); - } - else if (memcmp(config, "lon ", 4) == 0) { + } else if (memcmp(config, "lon ", 4) == 0) { _prefs.node_lon = atof(&config[4]); savePrefs(); Serial.println(" OK"); - } - else if (memcmp(config, "tx ", 3) == 0) { + } else if (memcmp(config, "tx ", 3) == 0) { _prefs.tx_power_dbm = atoi(&config[3]); savePrefs(); Serial.println(" OK - reboot to apply"); - } - else if (memcmp(config, "freq ", 5) == 0) { + } else if (memcmp(config, "freq ", 5) == 0) { _prefs.freq = atof(&config[5]); savePrefs(); Serial.println(" OK - reboot to apply"); - } - else { + } else { Serial.printf(" ERROR: unknown config: %s\n", config); } - } - else if (memcmp(command, "ver", 3) == 0) { + } else if (memcmp(command, "ver", 3) == 0) { Serial.println(FIRMWARE_VER_TEXT); - } - else if (memcmp(command, "help", 4) == 0) { + } else if (memcmp(command, "help", 4) == 0) { Serial.println("Commands:"); Serial.println(" set {name|lat|lon|freq|tx|af} {value}"); Serial.println(" card"); @@ -584,59 +516,50 @@ class MyMesh : public BaseChatMesh, ContactVisitor { Serial.println(" advert"); Serial.println(" reset path"); Serial.println(" public "); - } - else { - Serial.print(" ERROR: unknown command: "); - Serial.println(command); + } else { + Serial.print(" ERROR: unknown command: "); Serial.println(command); } } - void loop() - { + void loop() { BaseChatMesh::loop(); int len = strlen(command); - while (Serial.available() && len < sizeof(command) - 1) { + while (Serial.available() && len < sizeof(command)-1) { char c = Serial.read(); - if (c != '\n') { + if (c != '\n') { command[len++] = c; command[len] = 0; } Serial.print(c); } - if (len == sizeof(command) - 1) { // command buffer full - command[sizeof(command) - 1] = '\r'; + if (len == sizeof(command)-1) { // command buffer full + command[sizeof(command)-1] = '\r'; } - if (len > 0 && command[len - 1] == '\r') { // received complete line - command[len - 1] = 0; // replace newline with C string null terminator + if (len > 0 && command[len - 1] == '\r') { // received complete line + command[len - 1] = 0; // replace newline with C string null terminator handleCommand(command); - command[0] = 0; // reset command buffer + command[0] = 0; // reset command buffer } } }; StdRNG fast_rng; SimpleMeshTables tables; -MyMesh the_mesh(radio_driver, fast_rng, *new VolatileRTCClock(), - tables); // TODO: test with 'rtc_clock' in target.cpp +MyMesh the_mesh(radio_driver, fast_rng, *new VolatileRTCClock(), tables); // TODO: test with 'rtc_clock' in target.cpp -void halt() -{ - while (1) - ; +void halt() { + while (1) ; } -void setup() -{ +void setup() { Serial.begin(115200); board.begin(); - if (!radio_init()) { - halt(); - } + if (!radio_init()) { halt(); } fast_rng.begin(radio_get_rng_seed()); @@ -650,7 +573,7 @@ void setup() SPIFFS.begin(true); the_mesh.begin(SPIFFS); #else -#error "need to define filesystem" + #error "need to define filesystem" #endif radio_set_params(the_mesh.getFreqPref(), LORA_BW, LORA_SF, LORA_CR); @@ -659,10 +582,9 @@ void setup() the_mesh.showWelcome(); // send out initial Advertisement to the mesh - the_mesh.sendSelfAdvert(1200); // add slight delay + the_mesh.sendSelfAdvert(1200); // add slight delay } -void loop() -{ +void loop() { the_mesh.loop(); } From 69b431a517b99cc425521ad2840f938407c5658a Mon Sep 17 00:00:00 2001 From: hank Date: Sun, 1 Jun 2025 20:28:29 -0700 Subject: [PATCH 15/19] Re-applying 73a7a96, formatting, MyMesh reformat --- .clang-format | 4 +- examples/companion_radio/MyMesh.cpp | 504 ++++++++++------------------ variants/wio-e5-mini/target.cpp | 9 +- 3 files changed, 177 insertions(+), 340 deletions(-) diff --git a/.clang-format b/.clang-format index 80c7a10af..66ecd43a8 100644 --- a/.clang-format +++ b/.clang-format @@ -14,7 +14,7 @@ AllowAllParametersOfDeclarationOnNextLine: false AllowShortBlocksOnASingleLine: false AllowShortCaseLabelsOnASingleLine: false AllowShortFunctionsOnASingleLine: Inline -AllowShortIfStatementsOnASingleLine: false +AllowShortIfStatementsOnASingleLine: true AllowShortLoopsOnASingleLine: false AlwaysBreakAfterDefinitionReturnType: None AlwaysBreakAfterReturnType: None @@ -35,7 +35,7 @@ BraceWrapping: BeforeElse: true IndentBraces: false BreakBeforeBinaryOperators: None -BreakBeforeBraces: Stroustrup +BreakBeforeBraces: Attach BreakBeforeTernaryOperators: true BreakConstructorInitializersBeforeComma: false ColumnLimit: 110 diff --git a/examples/companion_radio/MyMesh.cpp b/examples/companion_radio/MyMesh.cpp index 1988c367c..e53022f60 100644 --- a/examples/companion_radio/MyMesh.cpp +++ b/examples/companion_radio/MyMesh.cpp @@ -72,8 +72,7 @@ #include "UITask.h" #endif -void MyMesh::loadMainIdentity() -{ +void MyMesh::loadMainIdentity() { if (!_identity_store->load("_main", self_id)) { self_id = radio_new_identity(); // create new random identity int count = 0; @@ -85,13 +84,11 @@ void MyMesh::loadMainIdentity() } } -bool MyMesh::saveMainIdentity(const mesh::LocalIdentity &identity) -{ +bool MyMesh::saveMainIdentity(const mesh::LocalIdentity &identity) { return _identity_store->save("_main", identity); } -void MyMesh::loadContacts() -{ +void MyMesh::loadContacts() { if (_fs->exists("/contacts3")) { #if defined(RP2040_PLATFORM) File file = _fs->open("/contacts3", "r"); @@ -118,20 +115,17 @@ void MyMesh::loadContacts() success = success && (file.read((uint8_t *)&c.gps_lat, 4) == 4); success = success && (file.read((uint8_t *)&c.gps_lon, 4) == 4); - if (!success) - break; // EOF + if (!success) break; // EOF c.id = mesh::Identity(pub_key); - if (!addContact(c)) - full = true; + if (!addContact(c)) full = true; } file.close(); } } } -void MyMesh::saveContacts() -{ +void MyMesh::saveContacts() { #if defined(NRF52_PLATFORM) || defined(STM32_PLATFORM) _fs->remove("/contacts3"); File file = _fs->open("/contacts3", FILE_O_WRITE); @@ -159,15 +153,13 @@ void MyMesh::saveContacts() success = success && (file.write((uint8_t *)&c.gps_lat, 4) == 4); success = success && (file.write((uint8_t *)&c.gps_lon, 4) == 4); - if (!success) - break; // write failed + if (!success) break; // write failed } file.close(); } } -void MyMesh::loadChannels() -{ +void MyMesh::loadChannels() { if (_fs->exists("/channels2")) { #if defined(RP2040_PLATFORM) File file = _fs->open("/channels2", "r"); @@ -185,13 +177,11 @@ void MyMesh::loadChannels() success = success && (file.read((uint8_t *)ch.name, 32) == 32); success = success && (file.read((uint8_t *)ch.channel.secret, 32) == 32); - if (!success) - break; // EOF + if (!success) break; // EOF if (setChannel(channel_idx, ch)) { channel_idx++; - } - else { + } else { full = true; } } @@ -200,8 +190,7 @@ void MyMesh::loadChannels() } } -void MyMesh::saveChannels() -{ +void MyMesh::saveChannels() { #if defined(NRF52_PLATFORM) || defined(STM32_PLATFORM) _fs->remove("/channels2"); File file = _fs->open("/channels2", FILE_O_WRITE); @@ -221,21 +210,18 @@ void MyMesh::saveChannels() success = success && (file.write((uint8_t *)ch.name, 32) == 32); success = success && (file.write((uint8_t *)ch.channel.secret, 32) == 32); - if (!success) - break; // write failed + if (!success) break; // write failed channel_idx++; } file.close(); } } -int MyMesh::getBlobByKey(const uint8_t key[], int key_len, uint8_t dest_buf[]) -{ +int MyMesh::getBlobByKey(const uint8_t key[], int key_len, uint8_t dest_buf[]) { char path[64]; char fname[18]; - if (key_len > 8) - key_len = 8; // just use first 8 bytes (prefix) + if (key_len > 8) key_len = 8; // just use first 8 bytes (prefix) mesh::Utils::toHex(fname, key, key_len); sprintf(path, "/bl/%s", fname); @@ -254,13 +240,11 @@ int MyMesh::getBlobByKey(const uint8_t key[], int key_len, uint8_t dest_buf[]) return 0; // not found } -bool MyMesh::putBlobByKey(const uint8_t key[], int key_len, const uint8_t src_buf[], int len) -{ +bool MyMesh::putBlobByKey(const uint8_t key[], int key_len, const uint8_t src_buf[], int len) { char path[64]; char fname[18]; - if (key_len > 8) - key_len = 8; // just use first 8 bytes (prefix) + if (key_len > 8) key_len = 8; // just use first 8 bytes (prefix) mesh::Utils::toHex(fname, key, key_len); sprintf(path, "/bl/%s", fname); @@ -275,37 +259,32 @@ bool MyMesh::putBlobByKey(const uint8_t key[], int key_len, const uint8_t src_bu if (f) { int n = f.write(src_buf, len); f.close(); - if (n == len) - return true; // success! + if (n == len) return true; // success! _fs->remove(path); // blob was only partially written! } return false; // error } -void MyMesh::writeOKFrame() -{ +void MyMesh::writeOKFrame() { uint8_t buf[1]; buf[0] = RESP_CODE_OK; _serial->writeFrame(buf, 1); } -void MyMesh::writeErrFrame(uint8_t err_code) -{ +void MyMesh::writeErrFrame(uint8_t err_code) { uint8_t buf[2]; buf[0] = RESP_CODE_ERR; buf[1] = err_code; _serial->writeFrame(buf, 2); } -void MyMesh::writeDisabledFrame() -{ +void MyMesh::writeDisabledFrame() { uint8_t buf[1]; buf[0] = RESP_CODE_DISABLED; _serial->writeFrame(buf, 1); } -void MyMesh::writeContactRespFrame(uint8_t code, const ContactInfo &contact) -{ +void MyMesh::writeContactRespFrame(uint8_t code, const ContactInfo &contact) { int i = 0; out_frame[i++] = code; memcpy(&out_frame[i], contact.id.pub_key, PUB_KEY_SIZE); @@ -328,8 +307,7 @@ void MyMesh::writeContactRespFrame(uint8_t code, const ContactInfo &contact) _serial->writeFrame(out_frame, i); } -void MyMesh::updateContactFromFrame(ContactInfo &contact, const uint8_t *frame, int len) -{ +void MyMesh::updateContactFromFrame(ContactInfo &contact, const uint8_t *frame, int len) { int i = 0; uint8_t code = frame[i++]; // eg. CMD_ADD_UPDATE_CONTACT memcpy(contact.id.pub_key, &frame[i], PUB_KEY_SIZE); @@ -351,19 +329,16 @@ void MyMesh::updateContactFromFrame(ContactInfo &contact, const uint8_t *frame, } } -void MyMesh::addToOfflineQueue(const uint8_t frame[], int len) -{ +void MyMesh::addToOfflineQueue(const uint8_t frame[], int len) { if (offline_queue_len >= OFFLINE_QUEUE_SIZE) { MESH_DEBUG_PRINTLN("ERROR: offline_queue is full!"); - } - else { + } else { offline_queue[offline_queue_len].len = len; memcpy(offline_queue[offline_queue_len].buf, frame, len); offline_queue_len++; } } -int MyMesh::getFromOfflineQueue(uint8_t frame[]) -{ +int MyMesh::getFromOfflineQueue(uint8_t frame[]) { if (offline_queue_len > 0) { // check offline queue size_t len = offline_queue[0].len; // take from top of queue memcpy(frame, offline_queue[0].buf, len); @@ -377,25 +352,20 @@ int MyMesh::getFromOfflineQueue(uint8_t frame[]) return 0; // queue is empty } -float MyMesh::getAirtimeBudgetFactor() const -{ +float MyMesh::getAirtimeBudgetFactor() const { return _prefs.airtime_factor; } -int MyMesh::getInterferenceThreshold() const -{ +int MyMesh::getInterferenceThreshold() const { return 0; // disabled for now, until currentRSSI() problem is resolved } -int MyMesh::calcRxDelay(float score, uint32_t air_time) const -{ - if (_prefs.rx_delay_base <= 0.0f) - return 0; +int MyMesh::calcRxDelay(float score, uint32_t air_time) const { + if (_prefs.rx_delay_base <= 0.0f) return 0; return (int)((pow(_prefs.rx_delay_base, 0.85f - score) - 1.0) * air_time); } -void MyMesh::logRxRaw(float snr, float rssi, const uint8_t raw[], int len) -{ +void MyMesh::logRxRaw(float snr, float rssi, const uint8_t raw[], int len) { if (_serial->isConnected() && len + 3 <= MAX_FRAME_SIZE) { int i = 0; out_frame[i++] = PUSH_CODE_LOG_RX_DATA; @@ -408,24 +378,20 @@ void MyMesh::logRxRaw(float snr, float rssi, const uint8_t raw[], int len) } } -bool MyMesh::isAutoAddEnabled() const -{ +bool MyMesh::isAutoAddEnabled() const { return (_prefs.manual_add_contacts & 1) == 0; } -void MyMesh::onDiscoveredContact(ContactInfo &contact, bool is_new) -{ +void MyMesh::onDiscoveredContact(ContactInfo &contact, bool is_new) { if (_serial->isConnected()) { if (!isAutoAddEnabled() && is_new) { writeContactRespFrame(PUSH_CODE_NEW_ADVERT, contact); - } - else { + } else { out_frame[0] = PUSH_CODE_ADVERT; memcpy(&out_frame[1], contact.id.pub_key, PUB_KEY_SIZE); _serial->writeFrame(out_frame, 1 + PUB_KEY_SIZE); } - } - else { + } else { #ifdef DISPLAY_CLASS ui_task.soundBuzzer(UIEventType::newContactMessage); #endif @@ -434,8 +400,7 @@ void MyMesh::onDiscoveredContact(ContactInfo &contact, bool is_new) dirty_contacts_expiry = futureMillis(LAZY_CONTACTS_WRITE_DELAY); } -void MyMesh::onContactPathUpdated(const ContactInfo &contact) -{ +void MyMesh::onContactPathUpdated(const ContactInfo &contact) { out_frame[0] = PUSH_CODE_PATH_UPDATED; memcpy(&out_frame[1], contact.id.pub_key, PUB_KEY_SIZE); _serial->writeFrame(out_frame, 1 + PUB_KEY_SIZE); // NOTE: app may not be connected @@ -443,8 +408,7 @@ void MyMesh::onContactPathUpdated(const ContactInfo &contact) dirty_contacts_expiry = futureMillis(LAZY_CONTACTS_WRITE_DELAY); } -bool MyMesh::processAck(const uint8_t *data) -{ +bool MyMesh::processAck(const uint8_t *data) { // see if matches any in a table for (int i = 0; i < EXPECTED_ACK_TABLE_SIZE; i++) { if (memcmp(data, &expected_ack_table[i].ack, 4) == 0) { // got an ACK from recipient @@ -463,16 +427,14 @@ bool MyMesh::processAck(const uint8_t *data) } void MyMesh::queueMessage(const ContactInfo &from, uint8_t txt_type, mesh::Packet *pkt, - uint32_t sender_timestamp, const uint8_t *extra, int extra_len, const char *text) -{ + uint32_t sender_timestamp, const uint8_t *extra, int extra_len, const char *text) { int i = 0; if (app_target_ver >= 3) { out_frame[i++] = RESP_CODE_CONTACT_MSG_RECV_V3; out_frame[i++] = (int8_t)(pkt->getSNR() * 4); out_frame[i++] = 0; // reserved1 out_frame[i++] = 0; // reserved2 - } - else { + } else { out_frame[i++] = RESP_CODE_CONTACT_MSG_RECV; } memcpy(&out_frame[i], from.id.pub_key, 6); @@ -497,8 +459,7 @@ void MyMesh::queueMessage(const ContactInfo &from, uint8_t txt_type, mesh::Packe uint8_t frame[1]; frame[0] = PUSH_CODE_MSG_WAITING; // send push 'tickle' _serial->writeFrame(frame, 1); - } - else { + } else { #ifdef DISPLAY_CLASS ui_task.soundBuzzer(UIEventType::contactMessage); #endif @@ -509,22 +470,19 @@ void MyMesh::queueMessage(const ContactInfo &from, uint8_t txt_type, mesh::Packe } void MyMesh::onMessageRecv(const ContactInfo &from, mesh::Packet *pkt, uint32_t sender_timestamp, - const char *text) -{ + const char *text) { markConnectionActive(from); // in case this is from a server, and we have a connection queueMessage(from, TXT_TYPE_PLAIN, pkt, sender_timestamp, NULL, 0, text); } void MyMesh::onCommandDataRecv(const ContactInfo &from, mesh::Packet *pkt, uint32_t sender_timestamp, - const char *text) -{ + const char *text) { markConnectionActive(from); // in case this is from a server, and we have a connection queueMessage(from, TXT_TYPE_CLI_DATA, pkt, sender_timestamp, NULL, 0, text); } void MyMesh::onSignedMessageRecv(const ContactInfo &from, mesh::Packet *pkt, uint32_t sender_timestamp, - const uint8_t *sender_prefix, const char *text) -{ + const uint8_t *sender_prefix, const char *text) { markConnectionActive(from); // from.sync_since change needs to be persisted dirty_contacts_expiry = futureMillis(LAZY_CONTACTS_WRITE_DELAY); @@ -532,16 +490,14 @@ void MyMesh::onSignedMessageRecv(const ContactInfo &from, mesh::Packet *pkt, uin } void MyMesh::onChannelMessageRecv(const mesh::GroupChannel &channel, mesh::Packet *pkt, uint32_t timestamp, - const char *text) -{ + const char *text) { int i = 0; if (app_target_ver >= 3) { out_frame[i++] = RESP_CODE_CHANNEL_MSG_RECV_V3; out_frame[i++] = (int8_t)(pkt->getSNR() * 4); out_frame[i++] = 0; // reserved1 out_frame[i++] = 0; // reserved2 - } - else { + } else { out_frame[i++] = RESP_CODE_CHANNEL_MSG_RECV; } @@ -564,8 +520,7 @@ void MyMesh::onChannelMessageRecv(const mesh::GroupChannel &channel, mesh::Packe uint8_t frame[1]; frame[0] = PUSH_CODE_MSG_WAITING; // send push 'tickle' _serial->writeFrame(frame, 1); - } - else { + } else { #ifdef DISPLAY_CLASS ui_task.soundBuzzer(UIEventType::channelMessage); #endif @@ -582,30 +537,26 @@ void MyMesh::onChannelMessageRecv(const mesh::GroupChannel &channel, mesh::Packe } uint8_t MyMesh::onContactRequest(const ContactInfo &contact, uint32_t sender_timestamp, const uint8_t *data, - uint8_t len, uint8_t *reply) -{ + uint8_t len, uint8_t *reply) { if (data[0] == REQ_TYPE_GET_TELEMETRY_DATA) { uint8_t permissions = 0; uint8_t cp = contact.flags >> 1; // LSB used as 'favourite' bit (so only use upper bits) if (_prefs.telemetry_mode_base == TELEM_MODE_ALLOW_ALL) { permissions = TELEM_PERM_BASE; - } - else if (_prefs.telemetry_mode_base == TELEM_MODE_ALLOW_FLAGS) { + } else if (_prefs.telemetry_mode_base == TELEM_MODE_ALLOW_FLAGS) { permissions = cp & TELEM_PERM_BASE; } if (_prefs.telemetry_mode_loc == TELEM_MODE_ALLOW_ALL) { permissions |= TELEM_PERM_LOCATION; - } - else if (_prefs.telemetry_mode_loc == TELEM_MODE_ALLOW_FLAGS) { + } else if (_prefs.telemetry_mode_loc == TELEM_MODE_ALLOW_FLAGS) { permissions |= cp & TELEM_PERM_LOCATION; } if (_prefs.telemetry_mode_env == TELEM_MODE_ALLOW_ALL) { permissions |= TELEM_PERM_ENVIRONMENT; - } - else if (_prefs.telemetry_mode_env == TELEM_MODE_ALLOW_FLAGS) { + } else if (_prefs.telemetry_mode_env == TELEM_MODE_ALLOW_FLAGS) { permissions |= cp & TELEM_PERM_ENVIRONMENT; } @@ -626,8 +577,7 @@ uint8_t MyMesh::onContactRequest(const ContactInfo &contact, uint32_t sender_tim return 0; // unknown } -void MyMesh::onContactResponse(const ContactInfo &contact, const uint8_t *data, uint8_t len) -{ +void MyMesh::onContactResponse(const ContactInfo &contact, const uint8_t *data, uint8_t len) { uint32_t tag; memcpy(&tag, data, 4); @@ -640,9 +590,8 @@ void MyMesh::onContactResponse(const ContactInfo &contact, const uint8_t *data, out_frame[i++] = PUSH_CODE_LOGIN_SUCCESS; out_frame[i++] = 0; // legacy: is_admin = false memcpy(&out_frame[i], contact.id.pub_key, 6); - i += 6; // pub_key_prefix - } - else if (data[4] == RESP_SERVER_LOGIN_OK) { // new login response + i += 6; // pub_key_prefix + } else if (data[4] == RESP_SERVER_LOGIN_OK) { // new login response uint16_t keep_alive_secs = ((uint16_t)data[5]) * 16; if (keep_alive_secs > 0) { startConnection(contact, keep_alive_secs); @@ -653,19 +602,17 @@ void MyMesh::onContactResponse(const ContactInfo &contact, const uint8_t *data, i += 6; // pub_key_prefix memcpy(&out_frame[i], &tag, 4); i += 4; // NEW: include server timestamp - } - else { + } else { out_frame[i++] = PUSH_CODE_LOGIN_FAIL; out_frame[i++] = 0; // reserved memcpy(&out_frame[i], contact.id.pub_key, 6); i += 6; // pub_key_prefix } _serial->writeFrame(out_frame, i); - } - else if (len > 4 && // check for status response - pending_status && - memcmp(&pending_status, contact.id.pub_key, 4) == 0 // legacy matching scheme - // FUTURE: tag == pending_status + } else if (len > 4 && // check for status response + pending_status && + memcmp(&pending_status, contact.id.pub_key, 4) == 0 // legacy matching scheme + // FUTURE: tag == pending_status ) { pending_status = 0; @@ -677,8 +624,7 @@ void MyMesh::onContactResponse(const ContactInfo &contact, const uint8_t *data, memcpy(&out_frame[i], &data[4], len - 4); i += (len - 4); _serial->writeFrame(out_frame, i); - } - else if (len > 4 && tag == pending_telemetry) { // check for telemetry response + } else if (len > 4 && tag == pending_telemetry) { // check for telemetry response pending_telemetry = 0; int i = 0; @@ -692,8 +638,7 @@ void MyMesh::onContactResponse(const ContactInfo &contact, const uint8_t *data, } } -void MyMesh::onRawDataRecv(mesh::Packet *packet) -{ +void MyMesh::onRawDataRecv(mesh::Packet *packet) { if (packet->payload_len + 4 > sizeof(out_frame)) { MESH_DEBUG_PRINTLN("onRawDataRecv(), payload_len too long: %d", packet->payload_len); return; @@ -708,15 +653,13 @@ void MyMesh::onRawDataRecv(mesh::Packet *packet) if (_serial->isConnected()) { _serial->writeFrame(out_frame, i); - } - else { + } else { MESH_DEBUG_PRINTLN("onRawDataRecv(), data received while app offline"); } } void MyMesh::onTraceRecv(mesh::Packet *packet, uint32_t tag, uint32_t auth_code, uint8_t flags, - const uint8_t *path_snrs, const uint8_t *path_hashes, uint8_t path_len) -{ + const uint8_t *path_snrs, const uint8_t *path_hashes, uint8_t path_len) { int i = 0; out_frame[i++] = PUSH_CODE_TRACE_DATA; out_frame[i++] = 0; // reserved @@ -734,18 +677,15 @@ void MyMesh::onTraceRecv(mesh::Packet *packet, uint32_t tag, uint32_t auth_code, if (_serial->isConnected()) { _serial->writeFrame(out_frame, i); - } - else { + } else { MESH_DEBUG_PRINTLN("onTraceRecv(), data received while app offline"); } } -uint32_t MyMesh::calcFloodTimeoutMillisFor(uint32_t pkt_airtime_millis) const -{ +uint32_t MyMesh::calcFloodTimeoutMillisFor(uint32_t pkt_airtime_millis) const { return SEND_TIMEOUT_BASE_MILLIS + (FLOOD_SEND_TIMEOUT_FACTOR * pkt_airtime_millis); } -uint32_t MyMesh::calcDirectTimeoutMillisFor(uint32_t pkt_airtime_millis, uint8_t path_len) const -{ +uint32_t MyMesh::calcDirectTimeoutMillisFor(uint32_t pkt_airtime_millis, uint8_t path_len) const { return SEND_TIMEOUT_BASE_MILLIS + ((pkt_airtime_millis * DIRECT_SEND_PERHOP_FACTOR + DIRECT_SEND_PERHOP_EXTRA_MILLIS) * (path_len + 1)); @@ -755,8 +695,7 @@ void MyMesh::onSendTimeout() {} MyMesh::MyMesh(mesh::Radio &radio, mesh::RNG &rng, mesh::RTCClock &rtc, SimpleMeshTables &tables) : BaseChatMesh(radio, *new ArduinoMillis(), rng, rtc, *new StaticPoolPacketManager(16), tables), - _serial(NULL), telemetry(MAX_PACKET_PAYLOAD - 4) -{ + _serial(NULL), telemetry(MAX_PACKET_PAYLOAD - 4) { _iter_started = false; offline_queue_len = 0; app_target_ver = 0; @@ -778,8 +717,7 @@ MyMesh::MyMesh(mesh::Radio &radio, mesh::RNG &rng, mesh::RTCClock &rtc, SimpleMe //_prefs.rx_delay_base = 10.0f; enable once new algo fixed } -void MyMesh::loadPrefsInt(const char *filename) -{ +void MyMesh::loadPrefsInt(const char *filename) { #if defined(RP2040_PLATFORM) File file = _fs->open(filename, "r"); #else @@ -820,8 +758,7 @@ void MyMesh::loadPrefsInt(const char *filename) } } -void MyMesh::begin(FILESYSTEM &fs, bool has_display) -{ +void MyMesh::begin(FILESYSTEM &fs, bool has_display) { _fs = &fs; BaseChatMesh::begin(); @@ -850,8 +787,7 @@ void MyMesh::begin(FILESYSTEM &fs, bool has_display) // load persisted prefs if (_fs->exists("/new_prefs")) { loadPrefsInt("/new_prefs"); // new filename - } - else if (_fs->exists("/node_prefs")) { + } else if (_fs->exists("/node_prefs")) { loadPrefsInt("/node_prefs"); savePrefs(); // save to new filename _fs->remove("/node_prefs"); // remove old @@ -863,15 +799,13 @@ void MyMesh::begin(FILESYSTEM &fs, bool has_display) if (has_display) { StdRNG rng; _active_ble_pin = rng.nextInt(100000, 999999); // random pin each session - } - else { + } else { _active_ble_pin = BLE_PIN_CODE; // otherwise static pin } #else _active_ble_pin = BLE_PIN_CODE; // otherwise static pin #endif - } - else { + } else { _active_ble_pin = _prefs.ble_pin; } #else @@ -889,27 +823,22 @@ void MyMesh::begin(FILESYSTEM &fs, bool has_display) radio_set_tx_power(_prefs.tx_power_dbm); } -const char *MyMesh::getNodeName() -{ +const char *MyMesh::getNodeName() { return _prefs.node_name; } -NodePrefs *MyMesh::getNodePrefs() -{ +NodePrefs *MyMesh::getNodePrefs() { return &_prefs; } -uint32_t MyMesh::getBLEPin() -{ +uint32_t MyMesh::getBLEPin() { return _active_ble_pin; } -void MyMesh::startInterface(BaseSerialInterface &serial) -{ +void MyMesh::startInterface(BaseSerialInterface &serial) { _serial = &serial; serial.enable(); } -void MyMesh::savePrefs() -{ +void MyMesh::savePrefs() { #if defined(NRF52_PLATFORM) || defined(STM32_PLATFORM) _fs->remove("/new_prefs"); File file = _fs->open("/new_prefs", FILE_O_WRITE); @@ -945,8 +874,7 @@ void MyMesh::savePrefs() } } -void MyMesh::handleCmdFrame(size_t len) -{ +void MyMesh::handleCmdFrame(size_t len) { if (cmd_frame[0] == CMD_DEVICE_QEURY && len >= 2) { // sent when app establishes connection app_target_ver = cmd_frame[1]; // which version of protocol does app understand @@ -965,9 +893,8 @@ void MyMesh::handleCmdFrame(size_t len) StrHelper::strzcpy((char *)&out_frame[i], FIRMWARE_VERSION, 20); i += 20; _serial->writeFrame(out_frame, i); - } - else if (cmd_frame[0] == CMD_APP_START && - len >= 8) { // sent when app establishes connection, respond with node ID + } else if (cmd_frame[0] == CMD_APP_START && + len >= 8) { // sent when app establishes connection, respond with node ID // cmd_frame[1..7] reserved future char *app_name = (char *)&cmd_frame[8]; cmd_frame[len] = 0; // make app_name null terminated @@ -1008,8 +935,7 @@ void MyMesh::handleCmdFrame(size_t len) memcpy(&out_frame[i], _prefs.node_name, tlen); i += tlen; _serial->writeFrame(out_frame, i); - } - else if (cmd_frame[0] == CMD_SEND_TXT_MSG && len >= 14) { + } else if (cmd_frame[0] == CMD_SEND_TXT_MSG && len >= 14) { int i = 1; uint8_t txt_type = cmd_frame[i++]; uint8_t attempt = cmd_frame[i++]; @@ -1029,15 +955,13 @@ void MyMesh::handleCmdFrame(size_t len) if (txt_type == TXT_TYPE_CLI_DATA) { result = sendCommandData(*recipient, msg_timestamp, attempt, text, est_timeout); expected_ack = 0; // no Ack expected - } - else { + } else { result = sendMessage(*recipient, msg_timestamp, attempt, text, expected_ack, est_timeout); } // TODO: add expected ACK to table if (result == MSG_SEND_FAILED) { writeErrFrame(ERR_CODE_TABLE_FULL); - } - else { + } else { if (expected_ack) { expected_ack_table[next_ack_idx].msg_sent = _ms->getMillis(); // add to circular table expected_ack_table[next_ack_idx].ack = expected_ack; @@ -1050,14 +974,12 @@ void MyMesh::handleCmdFrame(size_t len) memcpy(&out_frame[6], &est_timeout, 4); _serial->writeFrame(out_frame, 10); } - } - else { + } else { writeErrFrame(recipient == NULL ? ERR_CODE_NOT_FOUND : ERR_CODE_UNSUPPORTED_CMD); // unknown recipient, or unsuported TXT_TYPE_* } - } - else if (cmd_frame[0] == CMD_SEND_CHANNEL_TXT_MSG) { // send GroupChannel msg + } else if (cmd_frame[0] == CMD_SEND_CHANNEL_TXT_MSG) { // send GroupChannel msg int i = 1; uint8_t txt_type = cmd_frame[i++]; // should be TXT_TYPE_PLAIN uint8_t channel_idx = cmd_frame[i++]; @@ -1068,27 +990,22 @@ void MyMesh::handleCmdFrame(size_t len) if (txt_type != TXT_TYPE_PLAIN) { writeErrFrame(ERR_CODE_UNSUPPORTED_CMD); - } - else { + } else { ChannelDetails channel; bool success = getChannel(channel_idx, channel); if (success && sendGroupMessage(msg_timestamp, channel.channel, _prefs.node_name, text, len - i)) { writeOKFrame(); - } - else { + } else { writeErrFrame(ERR_CODE_NOT_FOUND); // bad channel_idx } } - } - else if (cmd_frame[0] == CMD_GET_CONTACTS) { // get Contact list + } else if (cmd_frame[0] == CMD_GET_CONTACTS) { // get Contact list if (_iter_started) { writeErrFrame(ERR_CODE_BAD_STATE); // iterator is currently busy - } - else { + } else { if (len >= 5) { // has optional 'since' param memcpy(&_iter_filter_since, &cmd_frame[1], 4); - } - else { + } else { _iter_filter_since = 0; } @@ -1103,17 +1020,14 @@ void MyMesh::handleCmdFrame(size_t len) _iter_started = true; _most_recent_lastmod = 0; } - } - else if (cmd_frame[0] == CMD_SET_ADVERT_NAME && len >= 2) { + } else if (cmd_frame[0] == CMD_SET_ADVERT_NAME && len >= 2) { int nlen = len - 1; - if (nlen > sizeof(_prefs.node_name) - 1) - nlen = sizeof(_prefs.node_name) - 1; // max len + if (nlen > sizeof(_prefs.node_name) - 1) nlen = sizeof(_prefs.node_name) - 1; // max len memcpy(_prefs.node_name, &cmd_frame[1], nlen); _prefs.node_name[nlen] = 0; // null terminator savePrefs(); writeOKFrame(); - } - else if (cmd_frame[0] == CMD_SET_ADVERT_LATLON && len >= 9) { + } else if (cmd_frame[0] == CMD_SET_ADVERT_LATLON && len >= 9) { int32_t lat, lon, alt = 0; memcpy(&lat, &cmd_frame[1], 4); memcpy(&lon, &cmd_frame[5], 4); @@ -1125,46 +1039,38 @@ void MyMesh::handleCmdFrame(size_t len) sensors.node_lon = ((double)lon) / 1000000.0; savePrefs(); writeOKFrame(); - } - else { + } else { writeErrFrame(ERR_CODE_ILLEGAL_ARG); // invalid geo coordinate } - } - else if (cmd_frame[0] == CMD_GET_DEVICE_TIME) { + } else if (cmd_frame[0] == CMD_GET_DEVICE_TIME) { uint8_t reply[5]; reply[0] = RESP_CODE_CURR_TIME; uint32_t now = getRTCClock()->getCurrentTime(); memcpy(&reply[1], &now, 4); _serial->writeFrame(reply, 5); - } - else if (cmd_frame[0] == CMD_SET_DEVICE_TIME && len >= 5) { + } else if (cmd_frame[0] == CMD_SET_DEVICE_TIME && len >= 5) { uint32_t secs; memcpy(&secs, &cmd_frame[1], 4); uint32_t curr = getRTCClock()->getCurrentTime(); if (secs >= curr) { getRTCClock()->setCurrentTime(secs); writeOKFrame(); - } - else { + } else { writeErrFrame(ERR_CODE_ILLEGAL_ARG); } - } - else if (cmd_frame[0] == CMD_SEND_SELF_ADVERT) { + } else if (cmd_frame[0] == CMD_SEND_SELF_ADVERT) { auto pkt = createSelfAdvert(_prefs.node_name, sensors.node_lat, sensors.node_lon); if (pkt) { if (len >= 2 && cmd_frame[1] == 1) { // optional param (1 = flood, 0 = zero hop) sendFlood(pkt); - } - else { + } else { sendZeroHop(pkt); } writeOKFrame(); - } - else { + } else { writeErrFrame(ERR_CODE_TABLE_FULL); } - } - else if (cmd_frame[0] == CMD_RESET_PATH && len >= 1 + 32) { + } else if (cmd_frame[0] == CMD_RESET_PATH && len >= 1 + 32) { uint8_t *pub_key = &cmd_frame[1]; ContactInfo *recipient = lookupContactByPubKey(pub_key, PUB_KEY_SIZE); if (recipient) { @@ -1172,12 +1078,10 @@ void MyMesh::handleCmdFrame(size_t len) // recipient->lastmod = ?? shouldn't be needed, app already has this version of contact dirty_contacts_expiry = futureMillis(LAZY_CONTACTS_WRITE_DELAY); writeOKFrame(); - } - else { + } else { writeErrFrame(ERR_CODE_NOT_FOUND); // unknown contact } - } - else if (cmd_frame[0] == CMD_ADD_UPDATE_CONTACT && len >= 1 + 32 + 2 + 1) { + } else if (cmd_frame[0] == CMD_ADD_UPDATE_CONTACT && len >= 1 + 32 + 2 + 1) { uint8_t *pub_key = &cmd_frame[1]; ContactInfo *recipient = lookupContactByPubKey(pub_key, PUB_KEY_SIZE); if (recipient) { @@ -1185,8 +1089,7 @@ void MyMesh::handleCmdFrame(size_t len) // recipient->lastmod = ?? shouldn't be needed, app already has this version of contact dirty_contacts_expiry = futureMillis(LAZY_CONTACTS_WRITE_DELAY); writeOKFrame(); - } - else { + } else { ContactInfo contact; updateContactFromFrame(contact, cmd_frame, len); contact.lastmod = getRTCClock()->getCurrentTime(); @@ -1194,49 +1097,40 @@ void MyMesh::handleCmdFrame(size_t len) if (addContact(contact)) { dirty_contacts_expiry = futureMillis(LAZY_CONTACTS_WRITE_DELAY); writeOKFrame(); - } - else { + } else { writeErrFrame(ERR_CODE_TABLE_FULL); } } - } - else if (cmd_frame[0] == CMD_REMOVE_CONTACT) { + } else if (cmd_frame[0] == CMD_REMOVE_CONTACT) { uint8_t *pub_key = &cmd_frame[1]; ContactInfo *recipient = lookupContactByPubKey(pub_key, PUB_KEY_SIZE); if (recipient && removeContact(*recipient)) { dirty_contacts_expiry = futureMillis(LAZY_CONTACTS_WRITE_DELAY); writeOKFrame(); - } - else { + } else { writeErrFrame(ERR_CODE_NOT_FOUND); // not found, or unable to remove } - } - else if (cmd_frame[0] == CMD_SHARE_CONTACT) { + } else if (cmd_frame[0] == CMD_SHARE_CONTACT) { uint8_t *pub_key = &cmd_frame[1]; ContactInfo *recipient = lookupContactByPubKey(pub_key, PUB_KEY_SIZE); if (recipient) { if (shareContactZeroHop(*recipient)) { writeOKFrame(); - } - else { + } else { writeErrFrame(ERR_CODE_TABLE_FULL); // unable to send } - } - else { + } else { writeErrFrame(ERR_CODE_NOT_FOUND); } - } - else if (cmd_frame[0] == CMD_GET_CONTACT_BY_KEY) { + } else if (cmd_frame[0] == CMD_GET_CONTACT_BY_KEY) { uint8_t *pub_key = &cmd_frame[1]; ContactInfo *contact = lookupContactByPubKey(pub_key, PUB_KEY_SIZE); if (contact) { writeContactRespFrame(RESP_CODE_CONTACT, *contact); - } - else { + } else { writeErrFrame(ERR_CODE_NOT_FOUND); // not found } - } - else if (cmd_frame[0] == CMD_EXPORT_CONTACT) { + } else if (cmd_frame[0] == CMD_EXPORT_CONTACT) { if (len < 1 + PUB_KEY_SIZE) { // export SELF auto pkt = createSelfAdvert(_prefs.node_name, sensors.node_lat, sensors.node_lon); @@ -1247,46 +1141,38 @@ void MyMesh::handleCmdFrame(size_t len) uint8_t out_len = pkt->writeTo(&out_frame[1]); releasePacket(pkt); // undo the obtainNewPacket() _serial->writeFrame(out_frame, out_len + 1); - } - else { + } else { writeErrFrame(ERR_CODE_TABLE_FULL); // Error } - } - else { + } else { uint8_t *pub_key = &cmd_frame[1]; ContactInfo *recipient = lookupContactByPubKey(pub_key, PUB_KEY_SIZE); uint8_t out_len; if (recipient && (out_len = exportContact(*recipient, &out_frame[1])) > 0) { out_frame[0] = RESP_CODE_EXPORT_CONTACT; _serial->writeFrame(out_frame, out_len + 1); - } - else { + } else { writeErrFrame(ERR_CODE_NOT_FOUND); // not found } } - } - else if (cmd_frame[0] == CMD_IMPORT_CONTACT && len > 2 + 32 + 64) { + } else if (cmd_frame[0] == CMD_IMPORT_CONTACT && len > 2 + 32 + 64) { if (importContact(&cmd_frame[1], len - 1)) { writeOKFrame(); - } - else { + } else { writeErrFrame(ERR_CODE_ILLEGAL_ARG); } - } - else if (cmd_frame[0] == CMD_SYNC_NEXT_MESSAGE) { + } else if (cmd_frame[0] == CMD_SYNC_NEXT_MESSAGE) { int out_len; if ((out_len = getFromOfflineQueue(out_frame)) > 0) { _serial->writeFrame(out_frame, out_len); #ifdef DISPLAY_CLASS ui_task.msgRead(offline_queue_len); #endif - } - else { + } else { out_frame[0] = RESP_CODE_NO_MORE_MESSAGES; _serial->writeFrame(out_frame, 1); } - } - else if (cmd_frame[0] == CMD_SET_RADIO_PARAMS) { + } else if (cmd_frame[0] == CMD_SET_RADIO_PARAMS) { int i = 1; uint32_t freq; memcpy(&freq, &cmd_frame[i], 4); @@ -1310,25 +1196,21 @@ void MyMesh::handleCmdFrame(size_t len) (uint32_t)cr); writeOKFrame(); - } - else { + } else { MESH_DEBUG_PRINTLN("Error: CMD_SET_RADIO_PARAMS: f=%d, bw=%d, sf=%d, cr=%d", freq, bw, (uint32_t)sf, (uint32_t)cr); writeErrFrame(ERR_CODE_ILLEGAL_ARG); } - } - else if (cmd_frame[0] == CMD_SET_RADIO_TX_POWER) { + } else if (cmd_frame[0] == CMD_SET_RADIO_TX_POWER) { if (cmd_frame[1] > MAX_LORA_TX_POWER) { writeErrFrame(ERR_CODE_ILLEGAL_ARG); - } - else { + } else { _prefs.tx_power_dbm = cmd_frame[1]; savePrefs(); radio_set_tx_power(_prefs.tx_power_dbm); writeOKFrame(); } - } - else if (cmd_frame[0] == CMD_SET_TUNING_PARAMS) { + } else if (cmd_frame[0] == CMD_SET_TUNING_PARAMS) { int i = 1; uint32_t rx, af; memcpy(&rx, &cmd_frame[i], 4); @@ -1339,8 +1221,7 @@ void MyMesh::handleCmdFrame(size_t len) _prefs.airtime_factor = ((float)af) / 1000.0f; savePrefs(); writeOKFrame(); - } - else if (cmd_frame[0] == CMD_SET_OTHER_PARAMS) { + } else if (cmd_frame[0] == CMD_SET_OTHER_PARAMS) { _prefs.manual_add_contacts = cmd_frame[1]; if (len >= 3) { _prefs.telemetry_mode_base = cmd_frame[2] & 0x03; // v5+ @@ -1349,21 +1230,18 @@ void MyMesh::handleCmdFrame(size_t len) } savePrefs(); writeOKFrame(); - } - else if (cmd_frame[0] == CMD_REBOOT && memcmp(&cmd_frame[1], "reboot", 6) == 0) { + } else if (cmd_frame[0] == CMD_REBOOT && memcmp(&cmd_frame[1], "reboot", 6) == 0) { if (dirty_contacts_expiry) { // is there are pending dirty contacts write needed? saveContacts(); } board.reboot(); - } - else if (cmd_frame[0] == CMD_GET_BATTERY_VOLTAGE) { + } else if (cmd_frame[0] == CMD_GET_BATTERY_VOLTAGE) { uint8_t reply[3]; reply[0] = RESP_CODE_BATTERY_VOLTAGE; uint16_t battery_millivolts = board.getBattMilliVolts(); memcpy(&reply[1], &battery_millivolts, 2); _serial->writeFrame(reply, 3); - } - else if (cmd_frame[0] == CMD_EXPORT_PRIVATE_KEY) { + } else if (cmd_frame[0] == CMD_EXPORT_PRIVATE_KEY) { #if ENABLE_PRIVATE_KEY_EXPORT uint8_t reply[65]; reply[0] = RESP_CODE_PRIVATE_KEY; @@ -1372,23 +1250,20 @@ void MyMesh::handleCmdFrame(size_t len) #else writeDisabledFrame(); #endif - } - else if (cmd_frame[0] == CMD_IMPORT_PRIVATE_KEY && len >= 65) { + } else if (cmd_frame[0] == CMD_IMPORT_PRIVATE_KEY && len >= 65) { #if ENABLE_PRIVATE_KEY_IMPORT mesh::LocalIdentity identity; identity.readFrom(&cmd_frame[1], 64); if (saveMainIdentity(identity)) { self_id = identity; writeOKFrame(); - } - else { + } else { writeErrFrame(ERR_CODE_FILE_IO_ERROR); } #else writeDisabledFrame(); #endif - } - else if (cmd_frame[0] == CMD_SEND_RAW_DATA && len >= 6) { + } else if (cmd_frame[0] == CMD_SEND_RAW_DATA && len >= 6) { int i = 1; int8_t path_len = cmd_frame[i++]; if (path_len >= 0 && i + path_len + 4 <= len) { // minimum 4 byte payload @@ -1398,16 +1273,13 @@ void MyMesh::handleCmdFrame(size_t len) if (pkt) { sendDirect(pkt, path, path_len); writeOKFrame(); - } - else { + } else { writeErrFrame(ERR_CODE_TABLE_FULL); } - } - else { + } else { writeErrFrame(ERR_CODE_UNSUPPORTED_CMD); // flood, not supported (yet) } - } - else if (cmd_frame[0] == CMD_SEND_LOGIN && len >= 1 + PUB_KEY_SIZE) { + } else if (cmd_frame[0] == CMD_SEND_LOGIN && len >= 1 + PUB_KEY_SIZE) { uint8_t *pub_key = &cmd_frame[1]; ContactInfo *recipient = lookupContactByPubKey(pub_key, PUB_KEY_SIZE); char *password = (char *)&cmd_frame[1 + PUB_KEY_SIZE]; @@ -1417,8 +1289,7 @@ void MyMesh::handleCmdFrame(size_t len) int result = sendLogin(*recipient, password, est_timeout); if (result == MSG_SEND_FAILED) { writeErrFrame(ERR_CODE_TABLE_FULL); - } - else { + } else { pending_telemetry = pending_status = 0; memcpy(&pending_login, recipient->id.pub_key, 4); // match this to onContactResponse() out_frame[0] = RESP_CODE_SENT; @@ -1427,12 +1298,10 @@ void MyMesh::handleCmdFrame(size_t len) memcpy(&out_frame[6], &est_timeout, 4); _serial->writeFrame(out_frame, 10); } - } - else { + } 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]; ContactInfo *recipient = lookupContactByPubKey(pub_key, PUB_KEY_SIZE); if (recipient) { @@ -1440,8 +1309,7 @@ void MyMesh::handleCmdFrame(size_t len) int result = sendRequest(*recipient, REQ_TYPE_GET_STATUS, tag, est_timeout); if (result == MSG_SEND_FAILED) { writeErrFrame(ERR_CODE_TABLE_FULL); - } - else { + } else { pending_telemetry = pending_login = 0; // FUTURE: pending_status = tag; // match this in onContactResponse() memcpy(&pending_status, recipient->id.pub_key, 4); // legacy matching scheme @@ -1451,12 +1319,10 @@ void MyMesh::handleCmdFrame(size_t len) memcpy(&out_frame[6], &est_timeout, 4); _serial->writeFrame(out_frame, 10); } - } - else { + } else { writeErrFrame(ERR_CODE_NOT_FOUND); // contact not found } - } - else if (cmd_frame[0] == CMD_SEND_TELEMETRY_REQ && len >= 4 + PUB_KEY_SIZE) { + } else if (cmd_frame[0] == CMD_SEND_TELEMETRY_REQ && len >= 4 + PUB_KEY_SIZE) { uint8_t *pub_key = &cmd_frame[4]; ContactInfo *recipient = lookupContactByPubKey(pub_key, PUB_KEY_SIZE); if (recipient) { @@ -1464,8 +1330,7 @@ void MyMesh::handleCmdFrame(size_t len) int result = sendRequest(*recipient, REQ_TYPE_GET_TELEMETRY_DATA, tag, est_timeout); if (result == MSG_SEND_FAILED) { writeErrFrame(ERR_CODE_TABLE_FULL); - } - else { + } else { pending_status = pending_login = 0; pending_telemetry = tag; // match this in onContactResponse() out_frame[0] = RESP_CODE_SENT; @@ -1474,26 +1339,21 @@ void MyMesh::handleCmdFrame(size_t len) memcpy(&out_frame[6], &est_timeout, 4); _serial->writeFrame(out_frame, 10); } - } - else { + } else { writeErrFrame(ERR_CODE_NOT_FOUND); // contact not found } - } - else if (cmd_frame[0] == CMD_HAS_CONNECTION && len >= 1 + PUB_KEY_SIZE) { + } else if (cmd_frame[0] == CMD_HAS_CONNECTION && len >= 1 + PUB_KEY_SIZE) { uint8_t *pub_key = &cmd_frame[1]; if (hasConnectionTo(pub_key)) { writeOKFrame(); - } - else { + } else { writeErrFrame(ERR_CODE_NOT_FOUND); } - } - else if (cmd_frame[0] == CMD_LOGOUT && len >= 1 + PUB_KEY_SIZE) { + } else if (cmd_frame[0] == CMD_LOGOUT && len >= 1 + PUB_KEY_SIZE) { uint8_t *pub_key = &cmd_frame[1]; stopConnection(pub_key); writeOKFrame(); - } - else if (cmd_frame[0] == CMD_GET_CHANNEL && len >= 2) { + } else if (cmd_frame[0] == CMD_GET_CHANNEL && len >= 2) { uint8_t channel_idx = cmd_frame[1]; ChannelDetails channel; if (getChannel(channel_idx, channel)) { @@ -1505,15 +1365,12 @@ void MyMesh::handleCmdFrame(size_t len) memcpy(&out_frame[i], channel.channel.secret, 16); i += 16; // NOTE: only 128-bit supported _serial->writeFrame(out_frame, i); - } - else { + } else { writeErrFrame(ERR_CODE_NOT_FOUND); } - } - else if (cmd_frame[0] == CMD_SET_CHANNEL && len >= 2 + 32 + 32) { + } else if (cmd_frame[0] == CMD_SET_CHANNEL && len >= 2 + 32 + 32) { writeErrFrame(ERR_CODE_UNSUPPORTED_CMD); // not supported (yet) - } - else if (cmd_frame[0] == CMD_SET_CHANNEL && len >= 2 + 32 + 16) { + } else if (cmd_frame[0] == CMD_SET_CHANNEL && len >= 2 + 32 + 16) { uint8_t channel_idx = cmd_frame[1]; ChannelDetails channel; StrHelper::strncpy(channel.name, (char *)&cmd_frame[2], 32); @@ -1522,12 +1379,10 @@ void MyMesh::handleCmdFrame(size_t len) if (setChannel(channel_idx, channel)) { saveChannels(); writeOKFrame(); - } - else { + } else { writeErrFrame(ERR_CODE_NOT_FOUND); // bad channel_idx } - } - else if (cmd_frame[0] == CMD_SIGN_START) { + } else if (cmd_frame[0] == CMD_SIGN_START) { out_frame[0] = RESP_CODE_SIGN_START; out_frame[1] = 0; // reserved uint32_t len = MAX_SIGN_DATA_LEN; @@ -1539,18 +1394,15 @@ void MyMesh::handleCmdFrame(size_t len) } sign_data = (uint8_t *)malloc(MAX_SIGN_DATA_LEN); sign_data_len = 0; - } - else if (cmd_frame[0] == CMD_SIGN_DATA && len > 1) { + } else if (cmd_frame[0] == CMD_SIGN_DATA && len > 1) { if (sign_data == NULL || sign_data_len + (len - 1) > MAX_SIGN_DATA_LEN) { writeErrFrame(sign_data == NULL ? ERR_CODE_BAD_STATE : ERR_CODE_TABLE_FULL); // error: too long - } - else { + } else { memcpy(&sign_data[sign_data_len], &cmd_frame[1], len - 1); sign_data_len += (len - 1); writeOKFrame(); } - } - else if (cmd_frame[0] == CMD_SIGN_FINISH) { + } else if (cmd_frame[0] == CMD_SIGN_FINISH) { if (sign_data) { self_id.sign(&out_frame[1], sign_data, sign_data_len); @@ -1559,12 +1411,10 @@ void MyMesh::handleCmdFrame(size_t len) out_frame[0] = RESP_CODE_SIGNATURE; _serial->writeFrame(out_frame, 1 + SIGNATURE_SIZE); - } - else { + } else { writeErrFrame(ERR_CODE_BAD_STATE); } - } - else if (cmd_frame[0] == CMD_SEND_TRACE_PATH && len > 10 && len - 10 < MAX_PATH_SIZE) { + } else if (cmd_frame[0] == CMD_SEND_TRACE_PATH && len > 10 && len - 10 < MAX_PATH_SIZE) { uint32_t tag, auth; memcpy(&tag, &cmd_frame[1], 4); memcpy(&auth, &cmd_frame[5], 4); @@ -1581,12 +1431,10 @@ void MyMesh::handleCmdFrame(size_t len) memcpy(&out_frame[2], &tag, 4); memcpy(&out_frame[6], &est_timeout, 4); _serial->writeFrame(out_frame, 10); - } - else { + } else { writeErrFrame(ERR_CODE_TABLE_FULL); } - } - else if (cmd_frame[0] == CMD_SET_DEVICE_PIN && len >= 5) { + } else if (cmd_frame[0] == CMD_SET_DEVICE_PIN && len >= 5) { // get pin from command frame uint32_t pin; @@ -1597,12 +1445,10 @@ void MyMesh::handleCmdFrame(size_t len) _prefs.ble_pin = pin; savePrefs(); writeOKFrame(); - } - else { + } else { writeErrFrame(ERR_CODE_ILLEGAL_ARG); } - } - else if (cmd_frame[0] == CMD_GET_CUSTOM_VARS) { + } else if (cmd_frame[0] == CMD_GET_CUSTOM_VARS) { out_frame[0] = RESP_CODE_CUSTOM_VARS; char *dp = (char *)&out_frame[1]; for (int i = 0; i < sensors.getNumSettings() && dp - (char *)&out_frame[1] < 140; i++) { @@ -1616,8 +1462,7 @@ void MyMesh::handleCmdFrame(size_t len) dp = strchr(dp, 0); } _serial->writeFrame(out_frame, dp - (char *)out_frame); - } - else if (cmd_frame[0] == CMD_SET_CUSTOM_VAR && len >= 4) { + } else if (cmd_frame[0] == CMD_SET_CUSTOM_VAR && len >= 4) { cmd_frame[len] = 0; char *sp = (char *)&cmd_frame[1]; char *np = strchr(sp, ':'); // look for separator char @@ -1626,31 +1471,26 @@ void MyMesh::handleCmdFrame(size_t len) bool success = sensors.setSettingValue(sp, np); if (success) { writeOKFrame(); - } - else { + } else { writeErrFrame(ERR_CODE_ILLEGAL_ARG); } - } - else { + } else { writeErrFrame(ERR_CODE_ILLEGAL_ARG); } - } - else { + } else { writeErrFrame(ERR_CODE_UNSUPPORTED_CMD); MESH_DEBUG_PRINTLN("ERROR: unknown command: %02X", cmd_frame[0]); } } -void MyMesh::loop() -{ +void MyMesh::loop() { BaseChatMesh::loop(); size_t len = _serial->checkRecvFrame(cmd_frame); if (len > 0) { handleCmdFrame(len); - } - else if (_iter_started // check if our ContactsIterator is 'running' - && !_serial->isWriteBusy() // don't spam the Serial Interface too quickly! + } else if (_iter_started // check if our ContactsIterator is 'running' + && !_serial->isWriteBusy() // don't spam the Serial Interface too quickly! ) { ContactInfo contact; if (_iter.hasNext(this, contact)) { @@ -1660,16 +1500,14 @@ void MyMesh::loop() _most_recent_lastmod = contact.lastmod; // save for the RESP_CODE_END_OF_CONTACTS frame } } - } - else { // EOF + } else { // EOF out_frame[0] = RESP_CODE_END_OF_CONTACTS; memcpy(&out_frame[1], &_most_recent_lastmod, 4); // include the most recent lastmod, so app can update their 'since' _serial->writeFrame(out_frame, 5); _iter_started = false; } - } - else if (!_serial->isWriteBusy()) { + } else if (!_serial->isWriteBusy()) { checkConnections(); } @@ -1685,15 +1523,13 @@ void MyMesh::loop() #endif } -bool MyMesh::advert() -{ +bool MyMesh::advert() { auto pkt = createSelfAdvert(_prefs.node_name, sensors.node_lat, sensors.node_lon); if (pkt) { sendZeroHop(pkt); writeOKFrame(); return true; - } - else { + } else { writeErrFrame(ERR_CODE_TABLE_FULL); return false; } diff --git a/variants/wio-e5-mini/target.cpp b/variants/wio-e5-mini/target.cpp index e3dd2ec76..7a2b0d394 100644 --- a/variants/wio-e5-mini/target.cpp +++ b/variants/wio-e5-mini/target.cpp @@ -18,7 +18,8 @@ static const Module::RfSwitchMode_t rfswitch_table[] = { }; VolatileRTCClock rtc_clock; -WIOE5SensorManager sensors; +BME280I2C bme; +WIOE5SensorManager sensors(bme); #ifndef LORA_CR #define LORA_CR 5 @@ -72,9 +73,9 @@ bool WIOE5SensorManager::querySensors(uint8_t requester_permissions, CayenneLPP& float temp(NAN), hum(NAN), pres(NAN); BME280::TempUnit tempUnit(BME280::TempUnit_Celsius); - BME280::PresUnit presUnit(BME280::PresUnit_hPa); + BME280::PresUnit presUnit(BME280::PresUnit_bar); - bme.read(pres, temp, hum, tempUnit, presUnit); + _bme->read(pres, temp, hum, tempUnit, presUnit); telemetry.addTemperature(TELEM_CHANNEL_SELF, temp); telemetry.addRelativeHumidity(TELEM_CHANNEL_SELF, hum); @@ -84,7 +85,7 @@ bool WIOE5SensorManager::querySensors(uint8_t requester_permissions, CayenneLPP& } bool WIOE5SensorManager::begin() { - has_bme = bme.begin(); + has_bme = _bme->begin(); return has_bme; } \ No newline at end of file From 4e2786c516a28c2feb3b25b0750a78dc2c26afc0 Mon Sep 17 00:00:00 2001 From: hank Date: Sun, 1 Jun 2025 20:28:29 -0700 Subject: [PATCH 16/19] Re-applying 73a7a96, formatting, MyMesh reformat --- .clang-format | 4 +- examples/companion_radio/MyMesh.cpp | 504 ++++++++++------------------ 2 files changed, 172 insertions(+), 336 deletions(-) diff --git a/.clang-format b/.clang-format index 80c7a10af..66ecd43a8 100644 --- a/.clang-format +++ b/.clang-format @@ -14,7 +14,7 @@ AllowAllParametersOfDeclarationOnNextLine: false AllowShortBlocksOnASingleLine: false AllowShortCaseLabelsOnASingleLine: false AllowShortFunctionsOnASingleLine: Inline -AllowShortIfStatementsOnASingleLine: false +AllowShortIfStatementsOnASingleLine: true AllowShortLoopsOnASingleLine: false AlwaysBreakAfterDefinitionReturnType: None AlwaysBreakAfterReturnType: None @@ -35,7 +35,7 @@ BraceWrapping: BeforeElse: true IndentBraces: false BreakBeforeBinaryOperators: None -BreakBeforeBraces: Stroustrup +BreakBeforeBraces: Attach BreakBeforeTernaryOperators: true BreakConstructorInitializersBeforeComma: false ColumnLimit: 110 diff --git a/examples/companion_radio/MyMesh.cpp b/examples/companion_radio/MyMesh.cpp index 1988c367c..e53022f60 100644 --- a/examples/companion_radio/MyMesh.cpp +++ b/examples/companion_radio/MyMesh.cpp @@ -72,8 +72,7 @@ #include "UITask.h" #endif -void MyMesh::loadMainIdentity() -{ +void MyMesh::loadMainIdentity() { if (!_identity_store->load("_main", self_id)) { self_id = radio_new_identity(); // create new random identity int count = 0; @@ -85,13 +84,11 @@ void MyMesh::loadMainIdentity() } } -bool MyMesh::saveMainIdentity(const mesh::LocalIdentity &identity) -{ +bool MyMesh::saveMainIdentity(const mesh::LocalIdentity &identity) { return _identity_store->save("_main", identity); } -void MyMesh::loadContacts() -{ +void MyMesh::loadContacts() { if (_fs->exists("/contacts3")) { #if defined(RP2040_PLATFORM) File file = _fs->open("/contacts3", "r"); @@ -118,20 +115,17 @@ void MyMesh::loadContacts() success = success && (file.read((uint8_t *)&c.gps_lat, 4) == 4); success = success && (file.read((uint8_t *)&c.gps_lon, 4) == 4); - if (!success) - break; // EOF + if (!success) break; // EOF c.id = mesh::Identity(pub_key); - if (!addContact(c)) - full = true; + if (!addContact(c)) full = true; } file.close(); } } } -void MyMesh::saveContacts() -{ +void MyMesh::saveContacts() { #if defined(NRF52_PLATFORM) || defined(STM32_PLATFORM) _fs->remove("/contacts3"); File file = _fs->open("/contacts3", FILE_O_WRITE); @@ -159,15 +153,13 @@ void MyMesh::saveContacts() success = success && (file.write((uint8_t *)&c.gps_lat, 4) == 4); success = success && (file.write((uint8_t *)&c.gps_lon, 4) == 4); - if (!success) - break; // write failed + if (!success) break; // write failed } file.close(); } } -void MyMesh::loadChannels() -{ +void MyMesh::loadChannels() { if (_fs->exists("/channels2")) { #if defined(RP2040_PLATFORM) File file = _fs->open("/channels2", "r"); @@ -185,13 +177,11 @@ void MyMesh::loadChannels() success = success && (file.read((uint8_t *)ch.name, 32) == 32); success = success && (file.read((uint8_t *)ch.channel.secret, 32) == 32); - if (!success) - break; // EOF + if (!success) break; // EOF if (setChannel(channel_idx, ch)) { channel_idx++; - } - else { + } else { full = true; } } @@ -200,8 +190,7 @@ void MyMesh::loadChannels() } } -void MyMesh::saveChannels() -{ +void MyMesh::saveChannels() { #if defined(NRF52_PLATFORM) || defined(STM32_PLATFORM) _fs->remove("/channels2"); File file = _fs->open("/channels2", FILE_O_WRITE); @@ -221,21 +210,18 @@ void MyMesh::saveChannels() success = success && (file.write((uint8_t *)ch.name, 32) == 32); success = success && (file.write((uint8_t *)ch.channel.secret, 32) == 32); - if (!success) - break; // write failed + if (!success) break; // write failed channel_idx++; } file.close(); } } -int MyMesh::getBlobByKey(const uint8_t key[], int key_len, uint8_t dest_buf[]) -{ +int MyMesh::getBlobByKey(const uint8_t key[], int key_len, uint8_t dest_buf[]) { char path[64]; char fname[18]; - if (key_len > 8) - key_len = 8; // just use first 8 bytes (prefix) + if (key_len > 8) key_len = 8; // just use first 8 bytes (prefix) mesh::Utils::toHex(fname, key, key_len); sprintf(path, "/bl/%s", fname); @@ -254,13 +240,11 @@ int MyMesh::getBlobByKey(const uint8_t key[], int key_len, uint8_t dest_buf[]) return 0; // not found } -bool MyMesh::putBlobByKey(const uint8_t key[], int key_len, const uint8_t src_buf[], int len) -{ +bool MyMesh::putBlobByKey(const uint8_t key[], int key_len, const uint8_t src_buf[], int len) { char path[64]; char fname[18]; - if (key_len > 8) - key_len = 8; // just use first 8 bytes (prefix) + if (key_len > 8) key_len = 8; // just use first 8 bytes (prefix) mesh::Utils::toHex(fname, key, key_len); sprintf(path, "/bl/%s", fname); @@ -275,37 +259,32 @@ bool MyMesh::putBlobByKey(const uint8_t key[], int key_len, const uint8_t src_bu if (f) { int n = f.write(src_buf, len); f.close(); - if (n == len) - return true; // success! + if (n == len) return true; // success! _fs->remove(path); // blob was only partially written! } return false; // error } -void MyMesh::writeOKFrame() -{ +void MyMesh::writeOKFrame() { uint8_t buf[1]; buf[0] = RESP_CODE_OK; _serial->writeFrame(buf, 1); } -void MyMesh::writeErrFrame(uint8_t err_code) -{ +void MyMesh::writeErrFrame(uint8_t err_code) { uint8_t buf[2]; buf[0] = RESP_CODE_ERR; buf[1] = err_code; _serial->writeFrame(buf, 2); } -void MyMesh::writeDisabledFrame() -{ +void MyMesh::writeDisabledFrame() { uint8_t buf[1]; buf[0] = RESP_CODE_DISABLED; _serial->writeFrame(buf, 1); } -void MyMesh::writeContactRespFrame(uint8_t code, const ContactInfo &contact) -{ +void MyMesh::writeContactRespFrame(uint8_t code, const ContactInfo &contact) { int i = 0; out_frame[i++] = code; memcpy(&out_frame[i], contact.id.pub_key, PUB_KEY_SIZE); @@ -328,8 +307,7 @@ void MyMesh::writeContactRespFrame(uint8_t code, const ContactInfo &contact) _serial->writeFrame(out_frame, i); } -void MyMesh::updateContactFromFrame(ContactInfo &contact, const uint8_t *frame, int len) -{ +void MyMesh::updateContactFromFrame(ContactInfo &contact, const uint8_t *frame, int len) { int i = 0; uint8_t code = frame[i++]; // eg. CMD_ADD_UPDATE_CONTACT memcpy(contact.id.pub_key, &frame[i], PUB_KEY_SIZE); @@ -351,19 +329,16 @@ void MyMesh::updateContactFromFrame(ContactInfo &contact, const uint8_t *frame, } } -void MyMesh::addToOfflineQueue(const uint8_t frame[], int len) -{ +void MyMesh::addToOfflineQueue(const uint8_t frame[], int len) { if (offline_queue_len >= OFFLINE_QUEUE_SIZE) { MESH_DEBUG_PRINTLN("ERROR: offline_queue is full!"); - } - else { + } else { offline_queue[offline_queue_len].len = len; memcpy(offline_queue[offline_queue_len].buf, frame, len); offline_queue_len++; } } -int MyMesh::getFromOfflineQueue(uint8_t frame[]) -{ +int MyMesh::getFromOfflineQueue(uint8_t frame[]) { if (offline_queue_len > 0) { // check offline queue size_t len = offline_queue[0].len; // take from top of queue memcpy(frame, offline_queue[0].buf, len); @@ -377,25 +352,20 @@ int MyMesh::getFromOfflineQueue(uint8_t frame[]) return 0; // queue is empty } -float MyMesh::getAirtimeBudgetFactor() const -{ +float MyMesh::getAirtimeBudgetFactor() const { return _prefs.airtime_factor; } -int MyMesh::getInterferenceThreshold() const -{ +int MyMesh::getInterferenceThreshold() const { return 0; // disabled for now, until currentRSSI() problem is resolved } -int MyMesh::calcRxDelay(float score, uint32_t air_time) const -{ - if (_prefs.rx_delay_base <= 0.0f) - return 0; +int MyMesh::calcRxDelay(float score, uint32_t air_time) const { + if (_prefs.rx_delay_base <= 0.0f) return 0; return (int)((pow(_prefs.rx_delay_base, 0.85f - score) - 1.0) * air_time); } -void MyMesh::logRxRaw(float snr, float rssi, const uint8_t raw[], int len) -{ +void MyMesh::logRxRaw(float snr, float rssi, const uint8_t raw[], int len) { if (_serial->isConnected() && len + 3 <= MAX_FRAME_SIZE) { int i = 0; out_frame[i++] = PUSH_CODE_LOG_RX_DATA; @@ -408,24 +378,20 @@ void MyMesh::logRxRaw(float snr, float rssi, const uint8_t raw[], int len) } } -bool MyMesh::isAutoAddEnabled() const -{ +bool MyMesh::isAutoAddEnabled() const { return (_prefs.manual_add_contacts & 1) == 0; } -void MyMesh::onDiscoveredContact(ContactInfo &contact, bool is_new) -{ +void MyMesh::onDiscoveredContact(ContactInfo &contact, bool is_new) { if (_serial->isConnected()) { if (!isAutoAddEnabled() && is_new) { writeContactRespFrame(PUSH_CODE_NEW_ADVERT, contact); - } - else { + } else { out_frame[0] = PUSH_CODE_ADVERT; memcpy(&out_frame[1], contact.id.pub_key, PUB_KEY_SIZE); _serial->writeFrame(out_frame, 1 + PUB_KEY_SIZE); } - } - else { + } else { #ifdef DISPLAY_CLASS ui_task.soundBuzzer(UIEventType::newContactMessage); #endif @@ -434,8 +400,7 @@ void MyMesh::onDiscoveredContact(ContactInfo &contact, bool is_new) dirty_contacts_expiry = futureMillis(LAZY_CONTACTS_WRITE_DELAY); } -void MyMesh::onContactPathUpdated(const ContactInfo &contact) -{ +void MyMesh::onContactPathUpdated(const ContactInfo &contact) { out_frame[0] = PUSH_CODE_PATH_UPDATED; memcpy(&out_frame[1], contact.id.pub_key, PUB_KEY_SIZE); _serial->writeFrame(out_frame, 1 + PUB_KEY_SIZE); // NOTE: app may not be connected @@ -443,8 +408,7 @@ void MyMesh::onContactPathUpdated(const ContactInfo &contact) dirty_contacts_expiry = futureMillis(LAZY_CONTACTS_WRITE_DELAY); } -bool MyMesh::processAck(const uint8_t *data) -{ +bool MyMesh::processAck(const uint8_t *data) { // see if matches any in a table for (int i = 0; i < EXPECTED_ACK_TABLE_SIZE; i++) { if (memcmp(data, &expected_ack_table[i].ack, 4) == 0) { // got an ACK from recipient @@ -463,16 +427,14 @@ bool MyMesh::processAck(const uint8_t *data) } void MyMesh::queueMessage(const ContactInfo &from, uint8_t txt_type, mesh::Packet *pkt, - uint32_t sender_timestamp, const uint8_t *extra, int extra_len, const char *text) -{ + uint32_t sender_timestamp, const uint8_t *extra, int extra_len, const char *text) { int i = 0; if (app_target_ver >= 3) { out_frame[i++] = RESP_CODE_CONTACT_MSG_RECV_V3; out_frame[i++] = (int8_t)(pkt->getSNR() * 4); out_frame[i++] = 0; // reserved1 out_frame[i++] = 0; // reserved2 - } - else { + } else { out_frame[i++] = RESP_CODE_CONTACT_MSG_RECV; } memcpy(&out_frame[i], from.id.pub_key, 6); @@ -497,8 +459,7 @@ void MyMesh::queueMessage(const ContactInfo &from, uint8_t txt_type, mesh::Packe uint8_t frame[1]; frame[0] = PUSH_CODE_MSG_WAITING; // send push 'tickle' _serial->writeFrame(frame, 1); - } - else { + } else { #ifdef DISPLAY_CLASS ui_task.soundBuzzer(UIEventType::contactMessage); #endif @@ -509,22 +470,19 @@ void MyMesh::queueMessage(const ContactInfo &from, uint8_t txt_type, mesh::Packe } void MyMesh::onMessageRecv(const ContactInfo &from, mesh::Packet *pkt, uint32_t sender_timestamp, - const char *text) -{ + const char *text) { markConnectionActive(from); // in case this is from a server, and we have a connection queueMessage(from, TXT_TYPE_PLAIN, pkt, sender_timestamp, NULL, 0, text); } void MyMesh::onCommandDataRecv(const ContactInfo &from, mesh::Packet *pkt, uint32_t sender_timestamp, - const char *text) -{ + const char *text) { markConnectionActive(from); // in case this is from a server, and we have a connection queueMessage(from, TXT_TYPE_CLI_DATA, pkt, sender_timestamp, NULL, 0, text); } void MyMesh::onSignedMessageRecv(const ContactInfo &from, mesh::Packet *pkt, uint32_t sender_timestamp, - const uint8_t *sender_prefix, const char *text) -{ + const uint8_t *sender_prefix, const char *text) { markConnectionActive(from); // from.sync_since change needs to be persisted dirty_contacts_expiry = futureMillis(LAZY_CONTACTS_WRITE_DELAY); @@ -532,16 +490,14 @@ void MyMesh::onSignedMessageRecv(const ContactInfo &from, mesh::Packet *pkt, uin } void MyMesh::onChannelMessageRecv(const mesh::GroupChannel &channel, mesh::Packet *pkt, uint32_t timestamp, - const char *text) -{ + const char *text) { int i = 0; if (app_target_ver >= 3) { out_frame[i++] = RESP_CODE_CHANNEL_MSG_RECV_V3; out_frame[i++] = (int8_t)(pkt->getSNR() * 4); out_frame[i++] = 0; // reserved1 out_frame[i++] = 0; // reserved2 - } - else { + } else { out_frame[i++] = RESP_CODE_CHANNEL_MSG_RECV; } @@ -564,8 +520,7 @@ void MyMesh::onChannelMessageRecv(const mesh::GroupChannel &channel, mesh::Packe uint8_t frame[1]; frame[0] = PUSH_CODE_MSG_WAITING; // send push 'tickle' _serial->writeFrame(frame, 1); - } - else { + } else { #ifdef DISPLAY_CLASS ui_task.soundBuzzer(UIEventType::channelMessage); #endif @@ -582,30 +537,26 @@ void MyMesh::onChannelMessageRecv(const mesh::GroupChannel &channel, mesh::Packe } uint8_t MyMesh::onContactRequest(const ContactInfo &contact, uint32_t sender_timestamp, const uint8_t *data, - uint8_t len, uint8_t *reply) -{ + uint8_t len, uint8_t *reply) { if (data[0] == REQ_TYPE_GET_TELEMETRY_DATA) { uint8_t permissions = 0; uint8_t cp = contact.flags >> 1; // LSB used as 'favourite' bit (so only use upper bits) if (_prefs.telemetry_mode_base == TELEM_MODE_ALLOW_ALL) { permissions = TELEM_PERM_BASE; - } - else if (_prefs.telemetry_mode_base == TELEM_MODE_ALLOW_FLAGS) { + } else if (_prefs.telemetry_mode_base == TELEM_MODE_ALLOW_FLAGS) { permissions = cp & TELEM_PERM_BASE; } if (_prefs.telemetry_mode_loc == TELEM_MODE_ALLOW_ALL) { permissions |= TELEM_PERM_LOCATION; - } - else if (_prefs.telemetry_mode_loc == TELEM_MODE_ALLOW_FLAGS) { + } else if (_prefs.telemetry_mode_loc == TELEM_MODE_ALLOW_FLAGS) { permissions |= cp & TELEM_PERM_LOCATION; } if (_prefs.telemetry_mode_env == TELEM_MODE_ALLOW_ALL) { permissions |= TELEM_PERM_ENVIRONMENT; - } - else if (_prefs.telemetry_mode_env == TELEM_MODE_ALLOW_FLAGS) { + } else if (_prefs.telemetry_mode_env == TELEM_MODE_ALLOW_FLAGS) { permissions |= cp & TELEM_PERM_ENVIRONMENT; } @@ -626,8 +577,7 @@ uint8_t MyMesh::onContactRequest(const ContactInfo &contact, uint32_t sender_tim return 0; // unknown } -void MyMesh::onContactResponse(const ContactInfo &contact, const uint8_t *data, uint8_t len) -{ +void MyMesh::onContactResponse(const ContactInfo &contact, const uint8_t *data, uint8_t len) { uint32_t tag; memcpy(&tag, data, 4); @@ -640,9 +590,8 @@ void MyMesh::onContactResponse(const ContactInfo &contact, const uint8_t *data, out_frame[i++] = PUSH_CODE_LOGIN_SUCCESS; out_frame[i++] = 0; // legacy: is_admin = false memcpy(&out_frame[i], contact.id.pub_key, 6); - i += 6; // pub_key_prefix - } - else if (data[4] == RESP_SERVER_LOGIN_OK) { // new login response + i += 6; // pub_key_prefix + } else if (data[4] == RESP_SERVER_LOGIN_OK) { // new login response uint16_t keep_alive_secs = ((uint16_t)data[5]) * 16; if (keep_alive_secs > 0) { startConnection(contact, keep_alive_secs); @@ -653,19 +602,17 @@ void MyMesh::onContactResponse(const ContactInfo &contact, const uint8_t *data, i += 6; // pub_key_prefix memcpy(&out_frame[i], &tag, 4); i += 4; // NEW: include server timestamp - } - else { + } else { out_frame[i++] = PUSH_CODE_LOGIN_FAIL; out_frame[i++] = 0; // reserved memcpy(&out_frame[i], contact.id.pub_key, 6); i += 6; // pub_key_prefix } _serial->writeFrame(out_frame, i); - } - else if (len > 4 && // check for status response - pending_status && - memcmp(&pending_status, contact.id.pub_key, 4) == 0 // legacy matching scheme - // FUTURE: tag == pending_status + } else if (len > 4 && // check for status response + pending_status && + memcmp(&pending_status, contact.id.pub_key, 4) == 0 // legacy matching scheme + // FUTURE: tag == pending_status ) { pending_status = 0; @@ -677,8 +624,7 @@ void MyMesh::onContactResponse(const ContactInfo &contact, const uint8_t *data, memcpy(&out_frame[i], &data[4], len - 4); i += (len - 4); _serial->writeFrame(out_frame, i); - } - else if (len > 4 && tag == pending_telemetry) { // check for telemetry response + } else if (len > 4 && tag == pending_telemetry) { // check for telemetry response pending_telemetry = 0; int i = 0; @@ -692,8 +638,7 @@ void MyMesh::onContactResponse(const ContactInfo &contact, const uint8_t *data, } } -void MyMesh::onRawDataRecv(mesh::Packet *packet) -{ +void MyMesh::onRawDataRecv(mesh::Packet *packet) { if (packet->payload_len + 4 > sizeof(out_frame)) { MESH_DEBUG_PRINTLN("onRawDataRecv(), payload_len too long: %d", packet->payload_len); return; @@ -708,15 +653,13 @@ void MyMesh::onRawDataRecv(mesh::Packet *packet) if (_serial->isConnected()) { _serial->writeFrame(out_frame, i); - } - else { + } else { MESH_DEBUG_PRINTLN("onRawDataRecv(), data received while app offline"); } } void MyMesh::onTraceRecv(mesh::Packet *packet, uint32_t tag, uint32_t auth_code, uint8_t flags, - const uint8_t *path_snrs, const uint8_t *path_hashes, uint8_t path_len) -{ + const uint8_t *path_snrs, const uint8_t *path_hashes, uint8_t path_len) { int i = 0; out_frame[i++] = PUSH_CODE_TRACE_DATA; out_frame[i++] = 0; // reserved @@ -734,18 +677,15 @@ void MyMesh::onTraceRecv(mesh::Packet *packet, uint32_t tag, uint32_t auth_code, if (_serial->isConnected()) { _serial->writeFrame(out_frame, i); - } - else { + } else { MESH_DEBUG_PRINTLN("onTraceRecv(), data received while app offline"); } } -uint32_t MyMesh::calcFloodTimeoutMillisFor(uint32_t pkt_airtime_millis) const -{ +uint32_t MyMesh::calcFloodTimeoutMillisFor(uint32_t pkt_airtime_millis) const { return SEND_TIMEOUT_BASE_MILLIS + (FLOOD_SEND_TIMEOUT_FACTOR * pkt_airtime_millis); } -uint32_t MyMesh::calcDirectTimeoutMillisFor(uint32_t pkt_airtime_millis, uint8_t path_len) const -{ +uint32_t MyMesh::calcDirectTimeoutMillisFor(uint32_t pkt_airtime_millis, uint8_t path_len) const { return SEND_TIMEOUT_BASE_MILLIS + ((pkt_airtime_millis * DIRECT_SEND_PERHOP_FACTOR + DIRECT_SEND_PERHOP_EXTRA_MILLIS) * (path_len + 1)); @@ -755,8 +695,7 @@ void MyMesh::onSendTimeout() {} MyMesh::MyMesh(mesh::Radio &radio, mesh::RNG &rng, mesh::RTCClock &rtc, SimpleMeshTables &tables) : BaseChatMesh(radio, *new ArduinoMillis(), rng, rtc, *new StaticPoolPacketManager(16), tables), - _serial(NULL), telemetry(MAX_PACKET_PAYLOAD - 4) -{ + _serial(NULL), telemetry(MAX_PACKET_PAYLOAD - 4) { _iter_started = false; offline_queue_len = 0; app_target_ver = 0; @@ -778,8 +717,7 @@ MyMesh::MyMesh(mesh::Radio &radio, mesh::RNG &rng, mesh::RTCClock &rtc, SimpleMe //_prefs.rx_delay_base = 10.0f; enable once new algo fixed } -void MyMesh::loadPrefsInt(const char *filename) -{ +void MyMesh::loadPrefsInt(const char *filename) { #if defined(RP2040_PLATFORM) File file = _fs->open(filename, "r"); #else @@ -820,8 +758,7 @@ void MyMesh::loadPrefsInt(const char *filename) } } -void MyMesh::begin(FILESYSTEM &fs, bool has_display) -{ +void MyMesh::begin(FILESYSTEM &fs, bool has_display) { _fs = &fs; BaseChatMesh::begin(); @@ -850,8 +787,7 @@ void MyMesh::begin(FILESYSTEM &fs, bool has_display) // load persisted prefs if (_fs->exists("/new_prefs")) { loadPrefsInt("/new_prefs"); // new filename - } - else if (_fs->exists("/node_prefs")) { + } else if (_fs->exists("/node_prefs")) { loadPrefsInt("/node_prefs"); savePrefs(); // save to new filename _fs->remove("/node_prefs"); // remove old @@ -863,15 +799,13 @@ void MyMesh::begin(FILESYSTEM &fs, bool has_display) if (has_display) { StdRNG rng; _active_ble_pin = rng.nextInt(100000, 999999); // random pin each session - } - else { + } else { _active_ble_pin = BLE_PIN_CODE; // otherwise static pin } #else _active_ble_pin = BLE_PIN_CODE; // otherwise static pin #endif - } - else { + } else { _active_ble_pin = _prefs.ble_pin; } #else @@ -889,27 +823,22 @@ void MyMesh::begin(FILESYSTEM &fs, bool has_display) radio_set_tx_power(_prefs.tx_power_dbm); } -const char *MyMesh::getNodeName() -{ +const char *MyMesh::getNodeName() { return _prefs.node_name; } -NodePrefs *MyMesh::getNodePrefs() -{ +NodePrefs *MyMesh::getNodePrefs() { return &_prefs; } -uint32_t MyMesh::getBLEPin() -{ +uint32_t MyMesh::getBLEPin() { return _active_ble_pin; } -void MyMesh::startInterface(BaseSerialInterface &serial) -{ +void MyMesh::startInterface(BaseSerialInterface &serial) { _serial = &serial; serial.enable(); } -void MyMesh::savePrefs() -{ +void MyMesh::savePrefs() { #if defined(NRF52_PLATFORM) || defined(STM32_PLATFORM) _fs->remove("/new_prefs"); File file = _fs->open("/new_prefs", FILE_O_WRITE); @@ -945,8 +874,7 @@ void MyMesh::savePrefs() } } -void MyMesh::handleCmdFrame(size_t len) -{ +void MyMesh::handleCmdFrame(size_t len) { if (cmd_frame[0] == CMD_DEVICE_QEURY && len >= 2) { // sent when app establishes connection app_target_ver = cmd_frame[1]; // which version of protocol does app understand @@ -965,9 +893,8 @@ void MyMesh::handleCmdFrame(size_t len) StrHelper::strzcpy((char *)&out_frame[i], FIRMWARE_VERSION, 20); i += 20; _serial->writeFrame(out_frame, i); - } - else if (cmd_frame[0] == CMD_APP_START && - len >= 8) { // sent when app establishes connection, respond with node ID + } else if (cmd_frame[0] == CMD_APP_START && + len >= 8) { // sent when app establishes connection, respond with node ID // cmd_frame[1..7] reserved future char *app_name = (char *)&cmd_frame[8]; cmd_frame[len] = 0; // make app_name null terminated @@ -1008,8 +935,7 @@ void MyMesh::handleCmdFrame(size_t len) memcpy(&out_frame[i], _prefs.node_name, tlen); i += tlen; _serial->writeFrame(out_frame, i); - } - else if (cmd_frame[0] == CMD_SEND_TXT_MSG && len >= 14) { + } else if (cmd_frame[0] == CMD_SEND_TXT_MSG && len >= 14) { int i = 1; uint8_t txt_type = cmd_frame[i++]; uint8_t attempt = cmd_frame[i++]; @@ -1029,15 +955,13 @@ void MyMesh::handleCmdFrame(size_t len) if (txt_type == TXT_TYPE_CLI_DATA) { result = sendCommandData(*recipient, msg_timestamp, attempt, text, est_timeout); expected_ack = 0; // no Ack expected - } - else { + } else { result = sendMessage(*recipient, msg_timestamp, attempt, text, expected_ack, est_timeout); } // TODO: add expected ACK to table if (result == MSG_SEND_FAILED) { writeErrFrame(ERR_CODE_TABLE_FULL); - } - else { + } else { if (expected_ack) { expected_ack_table[next_ack_idx].msg_sent = _ms->getMillis(); // add to circular table expected_ack_table[next_ack_idx].ack = expected_ack; @@ -1050,14 +974,12 @@ void MyMesh::handleCmdFrame(size_t len) memcpy(&out_frame[6], &est_timeout, 4); _serial->writeFrame(out_frame, 10); } - } - else { + } else { writeErrFrame(recipient == NULL ? ERR_CODE_NOT_FOUND : ERR_CODE_UNSUPPORTED_CMD); // unknown recipient, or unsuported TXT_TYPE_* } - } - else if (cmd_frame[0] == CMD_SEND_CHANNEL_TXT_MSG) { // send GroupChannel msg + } else if (cmd_frame[0] == CMD_SEND_CHANNEL_TXT_MSG) { // send GroupChannel msg int i = 1; uint8_t txt_type = cmd_frame[i++]; // should be TXT_TYPE_PLAIN uint8_t channel_idx = cmd_frame[i++]; @@ -1068,27 +990,22 @@ void MyMesh::handleCmdFrame(size_t len) if (txt_type != TXT_TYPE_PLAIN) { writeErrFrame(ERR_CODE_UNSUPPORTED_CMD); - } - else { + } else { ChannelDetails channel; bool success = getChannel(channel_idx, channel); if (success && sendGroupMessage(msg_timestamp, channel.channel, _prefs.node_name, text, len - i)) { writeOKFrame(); - } - else { + } else { writeErrFrame(ERR_CODE_NOT_FOUND); // bad channel_idx } } - } - else if (cmd_frame[0] == CMD_GET_CONTACTS) { // get Contact list + } else if (cmd_frame[0] == CMD_GET_CONTACTS) { // get Contact list if (_iter_started) { writeErrFrame(ERR_CODE_BAD_STATE); // iterator is currently busy - } - else { + } else { if (len >= 5) { // has optional 'since' param memcpy(&_iter_filter_since, &cmd_frame[1], 4); - } - else { + } else { _iter_filter_since = 0; } @@ -1103,17 +1020,14 @@ void MyMesh::handleCmdFrame(size_t len) _iter_started = true; _most_recent_lastmod = 0; } - } - else if (cmd_frame[0] == CMD_SET_ADVERT_NAME && len >= 2) { + } else if (cmd_frame[0] == CMD_SET_ADVERT_NAME && len >= 2) { int nlen = len - 1; - if (nlen > sizeof(_prefs.node_name) - 1) - nlen = sizeof(_prefs.node_name) - 1; // max len + if (nlen > sizeof(_prefs.node_name) - 1) nlen = sizeof(_prefs.node_name) - 1; // max len memcpy(_prefs.node_name, &cmd_frame[1], nlen); _prefs.node_name[nlen] = 0; // null terminator savePrefs(); writeOKFrame(); - } - else if (cmd_frame[0] == CMD_SET_ADVERT_LATLON && len >= 9) { + } else if (cmd_frame[0] == CMD_SET_ADVERT_LATLON && len >= 9) { int32_t lat, lon, alt = 0; memcpy(&lat, &cmd_frame[1], 4); memcpy(&lon, &cmd_frame[5], 4); @@ -1125,46 +1039,38 @@ void MyMesh::handleCmdFrame(size_t len) sensors.node_lon = ((double)lon) / 1000000.0; savePrefs(); writeOKFrame(); - } - else { + } else { writeErrFrame(ERR_CODE_ILLEGAL_ARG); // invalid geo coordinate } - } - else if (cmd_frame[0] == CMD_GET_DEVICE_TIME) { + } else if (cmd_frame[0] == CMD_GET_DEVICE_TIME) { uint8_t reply[5]; reply[0] = RESP_CODE_CURR_TIME; uint32_t now = getRTCClock()->getCurrentTime(); memcpy(&reply[1], &now, 4); _serial->writeFrame(reply, 5); - } - else if (cmd_frame[0] == CMD_SET_DEVICE_TIME && len >= 5) { + } else if (cmd_frame[0] == CMD_SET_DEVICE_TIME && len >= 5) { uint32_t secs; memcpy(&secs, &cmd_frame[1], 4); uint32_t curr = getRTCClock()->getCurrentTime(); if (secs >= curr) { getRTCClock()->setCurrentTime(secs); writeOKFrame(); - } - else { + } else { writeErrFrame(ERR_CODE_ILLEGAL_ARG); } - } - else if (cmd_frame[0] == CMD_SEND_SELF_ADVERT) { + } else if (cmd_frame[0] == CMD_SEND_SELF_ADVERT) { auto pkt = createSelfAdvert(_prefs.node_name, sensors.node_lat, sensors.node_lon); if (pkt) { if (len >= 2 && cmd_frame[1] == 1) { // optional param (1 = flood, 0 = zero hop) sendFlood(pkt); - } - else { + } else { sendZeroHop(pkt); } writeOKFrame(); - } - else { + } else { writeErrFrame(ERR_CODE_TABLE_FULL); } - } - else if (cmd_frame[0] == CMD_RESET_PATH && len >= 1 + 32) { + } else if (cmd_frame[0] == CMD_RESET_PATH && len >= 1 + 32) { uint8_t *pub_key = &cmd_frame[1]; ContactInfo *recipient = lookupContactByPubKey(pub_key, PUB_KEY_SIZE); if (recipient) { @@ -1172,12 +1078,10 @@ void MyMesh::handleCmdFrame(size_t len) // recipient->lastmod = ?? shouldn't be needed, app already has this version of contact dirty_contacts_expiry = futureMillis(LAZY_CONTACTS_WRITE_DELAY); writeOKFrame(); - } - else { + } else { writeErrFrame(ERR_CODE_NOT_FOUND); // unknown contact } - } - else if (cmd_frame[0] == CMD_ADD_UPDATE_CONTACT && len >= 1 + 32 + 2 + 1) { + } else if (cmd_frame[0] == CMD_ADD_UPDATE_CONTACT && len >= 1 + 32 + 2 + 1) { uint8_t *pub_key = &cmd_frame[1]; ContactInfo *recipient = lookupContactByPubKey(pub_key, PUB_KEY_SIZE); if (recipient) { @@ -1185,8 +1089,7 @@ void MyMesh::handleCmdFrame(size_t len) // recipient->lastmod = ?? shouldn't be needed, app already has this version of contact dirty_contacts_expiry = futureMillis(LAZY_CONTACTS_WRITE_DELAY); writeOKFrame(); - } - else { + } else { ContactInfo contact; updateContactFromFrame(contact, cmd_frame, len); contact.lastmod = getRTCClock()->getCurrentTime(); @@ -1194,49 +1097,40 @@ void MyMesh::handleCmdFrame(size_t len) if (addContact(contact)) { dirty_contacts_expiry = futureMillis(LAZY_CONTACTS_WRITE_DELAY); writeOKFrame(); - } - else { + } else { writeErrFrame(ERR_CODE_TABLE_FULL); } } - } - else if (cmd_frame[0] == CMD_REMOVE_CONTACT) { + } else if (cmd_frame[0] == CMD_REMOVE_CONTACT) { uint8_t *pub_key = &cmd_frame[1]; ContactInfo *recipient = lookupContactByPubKey(pub_key, PUB_KEY_SIZE); if (recipient && removeContact(*recipient)) { dirty_contacts_expiry = futureMillis(LAZY_CONTACTS_WRITE_DELAY); writeOKFrame(); - } - else { + } else { writeErrFrame(ERR_CODE_NOT_FOUND); // not found, or unable to remove } - } - else if (cmd_frame[0] == CMD_SHARE_CONTACT) { + } else if (cmd_frame[0] == CMD_SHARE_CONTACT) { uint8_t *pub_key = &cmd_frame[1]; ContactInfo *recipient = lookupContactByPubKey(pub_key, PUB_KEY_SIZE); if (recipient) { if (shareContactZeroHop(*recipient)) { writeOKFrame(); - } - else { + } else { writeErrFrame(ERR_CODE_TABLE_FULL); // unable to send } - } - else { + } else { writeErrFrame(ERR_CODE_NOT_FOUND); } - } - else if (cmd_frame[0] == CMD_GET_CONTACT_BY_KEY) { + } else if (cmd_frame[0] == CMD_GET_CONTACT_BY_KEY) { uint8_t *pub_key = &cmd_frame[1]; ContactInfo *contact = lookupContactByPubKey(pub_key, PUB_KEY_SIZE); if (contact) { writeContactRespFrame(RESP_CODE_CONTACT, *contact); - } - else { + } else { writeErrFrame(ERR_CODE_NOT_FOUND); // not found } - } - else if (cmd_frame[0] == CMD_EXPORT_CONTACT) { + } else if (cmd_frame[0] == CMD_EXPORT_CONTACT) { if (len < 1 + PUB_KEY_SIZE) { // export SELF auto pkt = createSelfAdvert(_prefs.node_name, sensors.node_lat, sensors.node_lon); @@ -1247,46 +1141,38 @@ void MyMesh::handleCmdFrame(size_t len) uint8_t out_len = pkt->writeTo(&out_frame[1]); releasePacket(pkt); // undo the obtainNewPacket() _serial->writeFrame(out_frame, out_len + 1); - } - else { + } else { writeErrFrame(ERR_CODE_TABLE_FULL); // Error } - } - else { + } else { uint8_t *pub_key = &cmd_frame[1]; ContactInfo *recipient = lookupContactByPubKey(pub_key, PUB_KEY_SIZE); uint8_t out_len; if (recipient && (out_len = exportContact(*recipient, &out_frame[1])) > 0) { out_frame[0] = RESP_CODE_EXPORT_CONTACT; _serial->writeFrame(out_frame, out_len + 1); - } - else { + } else { writeErrFrame(ERR_CODE_NOT_FOUND); // not found } } - } - else if (cmd_frame[0] == CMD_IMPORT_CONTACT && len > 2 + 32 + 64) { + } else if (cmd_frame[0] == CMD_IMPORT_CONTACT && len > 2 + 32 + 64) { if (importContact(&cmd_frame[1], len - 1)) { writeOKFrame(); - } - else { + } else { writeErrFrame(ERR_CODE_ILLEGAL_ARG); } - } - else if (cmd_frame[0] == CMD_SYNC_NEXT_MESSAGE) { + } else if (cmd_frame[0] == CMD_SYNC_NEXT_MESSAGE) { int out_len; if ((out_len = getFromOfflineQueue(out_frame)) > 0) { _serial->writeFrame(out_frame, out_len); #ifdef DISPLAY_CLASS ui_task.msgRead(offline_queue_len); #endif - } - else { + } else { out_frame[0] = RESP_CODE_NO_MORE_MESSAGES; _serial->writeFrame(out_frame, 1); } - } - else if (cmd_frame[0] == CMD_SET_RADIO_PARAMS) { + } else if (cmd_frame[0] == CMD_SET_RADIO_PARAMS) { int i = 1; uint32_t freq; memcpy(&freq, &cmd_frame[i], 4); @@ -1310,25 +1196,21 @@ void MyMesh::handleCmdFrame(size_t len) (uint32_t)cr); writeOKFrame(); - } - else { + } else { MESH_DEBUG_PRINTLN("Error: CMD_SET_RADIO_PARAMS: f=%d, bw=%d, sf=%d, cr=%d", freq, bw, (uint32_t)sf, (uint32_t)cr); writeErrFrame(ERR_CODE_ILLEGAL_ARG); } - } - else if (cmd_frame[0] == CMD_SET_RADIO_TX_POWER) { + } else if (cmd_frame[0] == CMD_SET_RADIO_TX_POWER) { if (cmd_frame[1] > MAX_LORA_TX_POWER) { writeErrFrame(ERR_CODE_ILLEGAL_ARG); - } - else { + } else { _prefs.tx_power_dbm = cmd_frame[1]; savePrefs(); radio_set_tx_power(_prefs.tx_power_dbm); writeOKFrame(); } - } - else if (cmd_frame[0] == CMD_SET_TUNING_PARAMS) { + } else if (cmd_frame[0] == CMD_SET_TUNING_PARAMS) { int i = 1; uint32_t rx, af; memcpy(&rx, &cmd_frame[i], 4); @@ -1339,8 +1221,7 @@ void MyMesh::handleCmdFrame(size_t len) _prefs.airtime_factor = ((float)af) / 1000.0f; savePrefs(); writeOKFrame(); - } - else if (cmd_frame[0] == CMD_SET_OTHER_PARAMS) { + } else if (cmd_frame[0] == CMD_SET_OTHER_PARAMS) { _prefs.manual_add_contacts = cmd_frame[1]; if (len >= 3) { _prefs.telemetry_mode_base = cmd_frame[2] & 0x03; // v5+ @@ -1349,21 +1230,18 @@ void MyMesh::handleCmdFrame(size_t len) } savePrefs(); writeOKFrame(); - } - else if (cmd_frame[0] == CMD_REBOOT && memcmp(&cmd_frame[1], "reboot", 6) == 0) { + } else if (cmd_frame[0] == CMD_REBOOT && memcmp(&cmd_frame[1], "reboot", 6) == 0) { if (dirty_contacts_expiry) { // is there are pending dirty contacts write needed? saveContacts(); } board.reboot(); - } - else if (cmd_frame[0] == CMD_GET_BATTERY_VOLTAGE) { + } else if (cmd_frame[0] == CMD_GET_BATTERY_VOLTAGE) { uint8_t reply[3]; reply[0] = RESP_CODE_BATTERY_VOLTAGE; uint16_t battery_millivolts = board.getBattMilliVolts(); memcpy(&reply[1], &battery_millivolts, 2); _serial->writeFrame(reply, 3); - } - else if (cmd_frame[0] == CMD_EXPORT_PRIVATE_KEY) { + } else if (cmd_frame[0] == CMD_EXPORT_PRIVATE_KEY) { #if ENABLE_PRIVATE_KEY_EXPORT uint8_t reply[65]; reply[0] = RESP_CODE_PRIVATE_KEY; @@ -1372,23 +1250,20 @@ void MyMesh::handleCmdFrame(size_t len) #else writeDisabledFrame(); #endif - } - else if (cmd_frame[0] == CMD_IMPORT_PRIVATE_KEY && len >= 65) { + } else if (cmd_frame[0] == CMD_IMPORT_PRIVATE_KEY && len >= 65) { #if ENABLE_PRIVATE_KEY_IMPORT mesh::LocalIdentity identity; identity.readFrom(&cmd_frame[1], 64); if (saveMainIdentity(identity)) { self_id = identity; writeOKFrame(); - } - else { + } else { writeErrFrame(ERR_CODE_FILE_IO_ERROR); } #else writeDisabledFrame(); #endif - } - else if (cmd_frame[0] == CMD_SEND_RAW_DATA && len >= 6) { + } else if (cmd_frame[0] == CMD_SEND_RAW_DATA && len >= 6) { int i = 1; int8_t path_len = cmd_frame[i++]; if (path_len >= 0 && i + path_len + 4 <= len) { // minimum 4 byte payload @@ -1398,16 +1273,13 @@ void MyMesh::handleCmdFrame(size_t len) if (pkt) { sendDirect(pkt, path, path_len); writeOKFrame(); - } - else { + } else { writeErrFrame(ERR_CODE_TABLE_FULL); } - } - else { + } else { writeErrFrame(ERR_CODE_UNSUPPORTED_CMD); // flood, not supported (yet) } - } - else if (cmd_frame[0] == CMD_SEND_LOGIN && len >= 1 + PUB_KEY_SIZE) { + } else if (cmd_frame[0] == CMD_SEND_LOGIN && len >= 1 + PUB_KEY_SIZE) { uint8_t *pub_key = &cmd_frame[1]; ContactInfo *recipient = lookupContactByPubKey(pub_key, PUB_KEY_SIZE); char *password = (char *)&cmd_frame[1 + PUB_KEY_SIZE]; @@ -1417,8 +1289,7 @@ void MyMesh::handleCmdFrame(size_t len) int result = sendLogin(*recipient, password, est_timeout); if (result == MSG_SEND_FAILED) { writeErrFrame(ERR_CODE_TABLE_FULL); - } - else { + } else { pending_telemetry = pending_status = 0; memcpy(&pending_login, recipient->id.pub_key, 4); // match this to onContactResponse() out_frame[0] = RESP_CODE_SENT; @@ -1427,12 +1298,10 @@ void MyMesh::handleCmdFrame(size_t len) memcpy(&out_frame[6], &est_timeout, 4); _serial->writeFrame(out_frame, 10); } - } - else { + } 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]; ContactInfo *recipient = lookupContactByPubKey(pub_key, PUB_KEY_SIZE); if (recipient) { @@ -1440,8 +1309,7 @@ void MyMesh::handleCmdFrame(size_t len) int result = sendRequest(*recipient, REQ_TYPE_GET_STATUS, tag, est_timeout); if (result == MSG_SEND_FAILED) { writeErrFrame(ERR_CODE_TABLE_FULL); - } - else { + } else { pending_telemetry = pending_login = 0; // FUTURE: pending_status = tag; // match this in onContactResponse() memcpy(&pending_status, recipient->id.pub_key, 4); // legacy matching scheme @@ -1451,12 +1319,10 @@ void MyMesh::handleCmdFrame(size_t len) memcpy(&out_frame[6], &est_timeout, 4); _serial->writeFrame(out_frame, 10); } - } - else { + } else { writeErrFrame(ERR_CODE_NOT_FOUND); // contact not found } - } - else if (cmd_frame[0] == CMD_SEND_TELEMETRY_REQ && len >= 4 + PUB_KEY_SIZE) { + } else if (cmd_frame[0] == CMD_SEND_TELEMETRY_REQ && len >= 4 + PUB_KEY_SIZE) { uint8_t *pub_key = &cmd_frame[4]; ContactInfo *recipient = lookupContactByPubKey(pub_key, PUB_KEY_SIZE); if (recipient) { @@ -1464,8 +1330,7 @@ void MyMesh::handleCmdFrame(size_t len) int result = sendRequest(*recipient, REQ_TYPE_GET_TELEMETRY_DATA, tag, est_timeout); if (result == MSG_SEND_FAILED) { writeErrFrame(ERR_CODE_TABLE_FULL); - } - else { + } else { pending_status = pending_login = 0; pending_telemetry = tag; // match this in onContactResponse() out_frame[0] = RESP_CODE_SENT; @@ -1474,26 +1339,21 @@ void MyMesh::handleCmdFrame(size_t len) memcpy(&out_frame[6], &est_timeout, 4); _serial->writeFrame(out_frame, 10); } - } - else { + } else { writeErrFrame(ERR_CODE_NOT_FOUND); // contact not found } - } - else if (cmd_frame[0] == CMD_HAS_CONNECTION && len >= 1 + PUB_KEY_SIZE) { + } else if (cmd_frame[0] == CMD_HAS_CONNECTION && len >= 1 + PUB_KEY_SIZE) { uint8_t *pub_key = &cmd_frame[1]; if (hasConnectionTo(pub_key)) { writeOKFrame(); - } - else { + } else { writeErrFrame(ERR_CODE_NOT_FOUND); } - } - else if (cmd_frame[0] == CMD_LOGOUT && len >= 1 + PUB_KEY_SIZE) { + } else if (cmd_frame[0] == CMD_LOGOUT && len >= 1 + PUB_KEY_SIZE) { uint8_t *pub_key = &cmd_frame[1]; stopConnection(pub_key); writeOKFrame(); - } - else if (cmd_frame[0] == CMD_GET_CHANNEL && len >= 2) { + } else if (cmd_frame[0] == CMD_GET_CHANNEL && len >= 2) { uint8_t channel_idx = cmd_frame[1]; ChannelDetails channel; if (getChannel(channel_idx, channel)) { @@ -1505,15 +1365,12 @@ void MyMesh::handleCmdFrame(size_t len) memcpy(&out_frame[i], channel.channel.secret, 16); i += 16; // NOTE: only 128-bit supported _serial->writeFrame(out_frame, i); - } - else { + } else { writeErrFrame(ERR_CODE_NOT_FOUND); } - } - else if (cmd_frame[0] == CMD_SET_CHANNEL && len >= 2 + 32 + 32) { + } else if (cmd_frame[0] == CMD_SET_CHANNEL && len >= 2 + 32 + 32) { writeErrFrame(ERR_CODE_UNSUPPORTED_CMD); // not supported (yet) - } - else if (cmd_frame[0] == CMD_SET_CHANNEL && len >= 2 + 32 + 16) { + } else if (cmd_frame[0] == CMD_SET_CHANNEL && len >= 2 + 32 + 16) { uint8_t channel_idx = cmd_frame[1]; ChannelDetails channel; StrHelper::strncpy(channel.name, (char *)&cmd_frame[2], 32); @@ -1522,12 +1379,10 @@ void MyMesh::handleCmdFrame(size_t len) if (setChannel(channel_idx, channel)) { saveChannels(); writeOKFrame(); - } - else { + } else { writeErrFrame(ERR_CODE_NOT_FOUND); // bad channel_idx } - } - else if (cmd_frame[0] == CMD_SIGN_START) { + } else if (cmd_frame[0] == CMD_SIGN_START) { out_frame[0] = RESP_CODE_SIGN_START; out_frame[1] = 0; // reserved uint32_t len = MAX_SIGN_DATA_LEN; @@ -1539,18 +1394,15 @@ void MyMesh::handleCmdFrame(size_t len) } sign_data = (uint8_t *)malloc(MAX_SIGN_DATA_LEN); sign_data_len = 0; - } - else if (cmd_frame[0] == CMD_SIGN_DATA && len > 1) { + } else if (cmd_frame[0] == CMD_SIGN_DATA && len > 1) { if (sign_data == NULL || sign_data_len + (len - 1) > MAX_SIGN_DATA_LEN) { writeErrFrame(sign_data == NULL ? ERR_CODE_BAD_STATE : ERR_CODE_TABLE_FULL); // error: too long - } - else { + } else { memcpy(&sign_data[sign_data_len], &cmd_frame[1], len - 1); sign_data_len += (len - 1); writeOKFrame(); } - } - else if (cmd_frame[0] == CMD_SIGN_FINISH) { + } else if (cmd_frame[0] == CMD_SIGN_FINISH) { if (sign_data) { self_id.sign(&out_frame[1], sign_data, sign_data_len); @@ -1559,12 +1411,10 @@ void MyMesh::handleCmdFrame(size_t len) out_frame[0] = RESP_CODE_SIGNATURE; _serial->writeFrame(out_frame, 1 + SIGNATURE_SIZE); - } - else { + } else { writeErrFrame(ERR_CODE_BAD_STATE); } - } - else if (cmd_frame[0] == CMD_SEND_TRACE_PATH && len > 10 && len - 10 < MAX_PATH_SIZE) { + } else if (cmd_frame[0] == CMD_SEND_TRACE_PATH && len > 10 && len - 10 < MAX_PATH_SIZE) { uint32_t tag, auth; memcpy(&tag, &cmd_frame[1], 4); memcpy(&auth, &cmd_frame[5], 4); @@ -1581,12 +1431,10 @@ void MyMesh::handleCmdFrame(size_t len) memcpy(&out_frame[2], &tag, 4); memcpy(&out_frame[6], &est_timeout, 4); _serial->writeFrame(out_frame, 10); - } - else { + } else { writeErrFrame(ERR_CODE_TABLE_FULL); } - } - else if (cmd_frame[0] == CMD_SET_DEVICE_PIN && len >= 5) { + } else if (cmd_frame[0] == CMD_SET_DEVICE_PIN && len >= 5) { // get pin from command frame uint32_t pin; @@ -1597,12 +1445,10 @@ void MyMesh::handleCmdFrame(size_t len) _prefs.ble_pin = pin; savePrefs(); writeOKFrame(); - } - else { + } else { writeErrFrame(ERR_CODE_ILLEGAL_ARG); } - } - else if (cmd_frame[0] == CMD_GET_CUSTOM_VARS) { + } else if (cmd_frame[0] == CMD_GET_CUSTOM_VARS) { out_frame[0] = RESP_CODE_CUSTOM_VARS; char *dp = (char *)&out_frame[1]; for (int i = 0; i < sensors.getNumSettings() && dp - (char *)&out_frame[1] < 140; i++) { @@ -1616,8 +1462,7 @@ void MyMesh::handleCmdFrame(size_t len) dp = strchr(dp, 0); } _serial->writeFrame(out_frame, dp - (char *)out_frame); - } - else if (cmd_frame[0] == CMD_SET_CUSTOM_VAR && len >= 4) { + } else if (cmd_frame[0] == CMD_SET_CUSTOM_VAR && len >= 4) { cmd_frame[len] = 0; char *sp = (char *)&cmd_frame[1]; char *np = strchr(sp, ':'); // look for separator char @@ -1626,31 +1471,26 @@ void MyMesh::handleCmdFrame(size_t len) bool success = sensors.setSettingValue(sp, np); if (success) { writeOKFrame(); - } - else { + } else { writeErrFrame(ERR_CODE_ILLEGAL_ARG); } - } - else { + } else { writeErrFrame(ERR_CODE_ILLEGAL_ARG); } - } - else { + } else { writeErrFrame(ERR_CODE_UNSUPPORTED_CMD); MESH_DEBUG_PRINTLN("ERROR: unknown command: %02X", cmd_frame[0]); } } -void MyMesh::loop() -{ +void MyMesh::loop() { BaseChatMesh::loop(); size_t len = _serial->checkRecvFrame(cmd_frame); if (len > 0) { handleCmdFrame(len); - } - else if (_iter_started // check if our ContactsIterator is 'running' - && !_serial->isWriteBusy() // don't spam the Serial Interface too quickly! + } else if (_iter_started // check if our ContactsIterator is 'running' + && !_serial->isWriteBusy() // don't spam the Serial Interface too quickly! ) { ContactInfo contact; if (_iter.hasNext(this, contact)) { @@ -1660,16 +1500,14 @@ void MyMesh::loop() _most_recent_lastmod = contact.lastmod; // save for the RESP_CODE_END_OF_CONTACTS frame } } - } - else { // EOF + } else { // EOF out_frame[0] = RESP_CODE_END_OF_CONTACTS; memcpy(&out_frame[1], &_most_recent_lastmod, 4); // include the most recent lastmod, so app can update their 'since' _serial->writeFrame(out_frame, 5); _iter_started = false; } - } - else if (!_serial->isWriteBusy()) { + } else if (!_serial->isWriteBusy()) { checkConnections(); } @@ -1685,15 +1523,13 @@ void MyMesh::loop() #endif } -bool MyMesh::advert() -{ +bool MyMesh::advert() { auto pkt = createSelfAdvert(_prefs.node_name, sensors.node_lat, sensors.node_lon); if (pkt) { sendZeroHop(pkt); writeOKFrame(); return true; - } - else { + } else { writeErrFrame(ERR_CODE_TABLE_FULL); return false; } From 9fe218e0d8e67322c1377b380cfee95fa7ec0a3c Mon Sep 17 00:00:00 2001 From: hank Date: Sun, 1 Jun 2025 20:41:04 -0700 Subject: [PATCH 17/19] Reverting format changes to NodePrefs But changing to pragma once. --- examples/companion_radio/NodePrefs.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/examples/companion_radio/NodePrefs.h b/examples/companion_radio/NodePrefs.h index 44d7ecbf2..4fd0fd3b4 100644 --- a/examples/companion_radio/NodePrefs.h +++ b/examples/companion_radio/NodePrefs.h @@ -1,11 +1,11 @@ #pragma once #include // For uint8_t, uint32_t -#define TELEM_MODE_DENY 0 -#define TELEM_MODE_ALLOW_FLAGS 1 // use contact.flags -#define TELEM_MODE_ALLOW_ALL 2 +#define TELEM_MODE_DENY 0 +#define TELEM_MODE_ALLOW_FLAGS 1 // use contact.flags +#define TELEM_MODE_ALLOW_ALL 2 -struct NodePrefs { // persisted to file +struct NodePrefs { // persisted to file float airtime_factor; char node_name[32]; float freq; From 33d5f85556b1bba24f48661e20301251bd406201 Mon Sep 17 00:00:00 2001 From: hank Date: Sun, 1 Jun 2025 20:42:40 -0700 Subject: [PATCH 18/19] Re-merging 92c2963 --- variants/wio-e5-mini/target.cpp | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/variants/wio-e5-mini/target.cpp b/variants/wio-e5-mini/target.cpp index 7a2b0d394..e3dd2ec76 100644 --- a/variants/wio-e5-mini/target.cpp +++ b/variants/wio-e5-mini/target.cpp @@ -18,8 +18,7 @@ static const Module::RfSwitchMode_t rfswitch_table[] = { }; VolatileRTCClock rtc_clock; -BME280I2C bme; -WIOE5SensorManager sensors(bme); +WIOE5SensorManager sensors; #ifndef LORA_CR #define LORA_CR 5 @@ -73,9 +72,9 @@ bool WIOE5SensorManager::querySensors(uint8_t requester_permissions, CayenneLPP& float temp(NAN), hum(NAN), pres(NAN); BME280::TempUnit tempUnit(BME280::TempUnit_Celsius); - BME280::PresUnit presUnit(BME280::PresUnit_bar); + BME280::PresUnit presUnit(BME280::PresUnit_hPa); - _bme->read(pres, temp, hum, tempUnit, presUnit); + bme.read(pres, temp, hum, tempUnit, presUnit); telemetry.addTemperature(TELEM_CHANNEL_SELF, temp); telemetry.addRelativeHumidity(TELEM_CHANNEL_SELF, hum); @@ -85,7 +84,7 @@ bool WIOE5SensorManager::querySensors(uint8_t requester_permissions, CayenneLPP& } bool WIOE5SensorManager::begin() { - has_bme = _bme->begin(); + has_bme = bme.begin(); return has_bme; } \ No newline at end of file From 884d8f1a987af3fcd0bb8368cd271e5004b3682b Mon Sep 17 00:00:00 2001 From: hank Date: Sun, 1 Jun 2025 20:45:18 -0700 Subject: [PATCH 19/19] Reverting UITask.h changes --- examples/companion_radio/UITask.h | 43 +++++++++++++++++++------------ 1 file changed, 26 insertions(+), 17 deletions(-) diff --git a/examples/companion_radio/UITask.h b/examples/companion_radio/UITask.h index f52c0961c..acf5237ea 100644 --- a/examples/companion_radio/UITask.h +++ b/examples/companion_radio/UITask.h @@ -1,43 +1,52 @@ #pragma once + #include #include #include #ifdef PIN_BUZZER -#include + #include #endif -#include "Button.h" #include "NodePrefs.h" +#include "Button.h" -enum class UIEventType { none, contactMessage, channelMessage, roomMessage, newContactMessage, ack }; + enum class UIEventType +{ + none, + contactMessage, + channelMessage, + roomMessage, + newContactMessage, + ack +}; class UITask { - DisplayDriver *_display; - mesh::MainBoard *_board; + DisplayDriver* _display; + mesh::MainBoard* _board; #ifdef PIN_BUZZER genericBuzzer buzzer; #endif unsigned long _next_refresh, _auto_off; bool _connected; uint32_t _pin_code; - NodePrefs *_node_prefs; + NodePrefs* _node_prefs; char _version_info[32]; char _origin[62]; char _msg[80]; int _msgcount; bool _need_refresh = true; - bool _displayWasOn = false; // Track display state before button press + bool _displayWasOn = false; // Track display state before button press // Button handlers #if defined(PIN_USER_BTN) || defined(PIN_USER_BTN_ANA) - Button *_userButton = nullptr; + Button* _userButton = nullptr; #endif void renderCurrScreen(); void userLedHandler(); void renderBatteryIndicator(uint16_t batteryMilliVolts); - + // Button action handlers void handleButtonAnyPress(); void handleButtonShortPress(); @@ -45,21 +54,21 @@ class UITask { void handleButtonTriplePress(); void handleButtonLongPress(); + public: - UITask(mesh::MainBoard *board) : _board(board), _display(NULL) - { - _next_refresh = 0; - _connected = false; + + UITask(mesh::MainBoard* board) : _board(board), _display(NULL) { + _next_refresh = 0; + _connected = false; } - void begin(DisplayDriver *display, NodePrefs *node_prefs, const char *build_date, - const char *firmware_version, uint32_t pin_code); + void begin(DisplayDriver* display, NodePrefs* node_prefs, const char* build_date, const char* firmware_version, uint32_t pin_code); void setHasConnection(bool connected) { _connected = connected; } bool hasDisplay() const { return _display != NULL; } void clearMsgPreview(); void msgRead(int msgcount); - void newMsg(uint8_t path_len, const char *from_name, const char *text, int msgcount); + void newMsg(uint8_t path_len, const char* from_name, const char* text, int msgcount); void soundBuzzer(UIEventType bet = UIEventType::none); void shutdown(bool restart = false); void loop(); -}; \ No newline at end of file +};