diff --git a/boards/seeed-xiao-afruitnrf52-nrf52840.json b/boards/seeed-xiao-afruitnrf52-nrf52840.json new file mode 100644 index 00000000..78855cd7 --- /dev/null +++ b/boards/seeed-xiao-afruitnrf52-nrf52840.json @@ -0,0 +1,61 @@ +{ + "build": { + "arduino": { + "ldscript": "nrf52840_s140_v7.ld" + }, + "core": "nRF5", + "cpu": "cortex-m4", + "extra_flags": "-DARDUINO_Seeed_XIAO_nRF52840 -DNRF52840_XXAA -DSEEED_XIAO_NRF52840 ", + "f_cpu": "64000000L", + "hwids": [ + [ "0x2886", "0x8044" ], + [ "0x2886", "0x0044" ] + ], + "mcu": "nrf52840", + "variant": "Seeed_XIAO_nRF52840", + "softdevice": { + "sd_flags": "-DS140", + "sd_name": "s140", + "sd_version": "7.3.0", + "sd_fwid": "0x0123" + }, + "bsp": { + "name": "adafruit" + }, + "bootloader": { + "settings_addr": "0xFF000" + }, + "usb_product": "XIAO nRF52840" + }, + "connectivity": [ + "bluetooth" + ], + "debug": { + "jlink_device": "nRF52840_xxAA", + "openocd_target": "nrf52.cfg", + "svd_path": "nrf52840.svd" + }, + "frameworks": [ + "arduino" + ], + "name": "Seeed Studio XIAO nRF52840", + "upload": { + "maximum_ram_size": 237568, + "maximum_size": 811008, + "protocol": "nrfutil", + "speed": 115200, + "protocols": [ + "jlink", + "nrfjprog", + "nrfutil", + "cmsis-dap", + "sam-ba", + "blackmagic" + ], + "use_1200bps_touch": true, + "require_upload_port": true, + "wait_for_upload_port": true + }, + "url": "https://wiki.seeedstudio.com/XIAO_BLE", + "vendor": "Seeed Studio" +} diff --git a/boards/t_beams3_supreme.json b/boards/t_beams3_supreme.json new file mode 100644 index 00000000..6a725247 --- /dev/null +++ b/boards/t_beams3_supreme.json @@ -0,0 +1,51 @@ +{ + "build": { + "arduino":{ + "ldscript": "esp32s3_out.ld", + "partitions": "default.csv", + "memory_type": "qio_qspi" + }, + "core": "esp32", + "extra_flags": [ + "-DARDUINO_USB_MODE=1", + "-DARDUINO_USB_CDC_ON_BOOT=1", + "-DARDUINO_RUNNING_CORE=1", + "-DARDUINO_EVENT_RUNNING_CORE=1" + ], + "f_cpu": "240000000L", + "f_flash": "80000000L", + "flash_mode": "qio", + "hwids": [ + [ + "0x303A", + "0x1001" + ] + ], + "mcu": "esp32s3", + "variant": "esp32s3" + }, + "connectivity": [ + "wifi" + ], + "debug": { + "default_tool": "esp-builtin", + "onboard_tools": [ + "esp-builtin" + ], + "openocd_target": "esp32s3.cfg" + }, + "frameworks": [ + "arduino", + "espidf" + ], + "name": "LilyGo T-Beam supreme (8MB Flash 8MB PSRAM)", + "upload": { + "flash_size": "8MB", + "maximum_ram_size": 327680, + "maximum_size": 8388608, + "require_upload_port": true, + "speed": 460800 + }, + "url": "https://www.lilygo.cc/products/t-beamsupreme-m", + "vendor": "LilyGo" + } \ No newline at end of file diff --git a/examples/companion_radio/UITask.cpp b/examples/companion_radio/UITask.cpp index c42bb094..7448f303 100644 --- a/examples/companion_radio/UITask.cpp +++ b/examples/companion_radio/UITask.cpp @@ -25,16 +25,30 @@ static const uint8_t meshcore_logo [] PROGMEM = { 0xe3, 0xe3, 0x8f, 0xff, 0x1f, 0xfc, 0x3c, 0x0e, 0x1f, 0xf8, 0xff, 0xf8, 0x70, 0x3c, 0x7f, 0xf8, }; -void UITask::begin(DisplayDriver* display, const char* node_name, const char* build_date, uint32_t pin_code) { +void UITask::begin(DisplayDriver* display, const char* node_name, const char* build_date, const char* firmware_version, uint32_t pin_code) { _display = display; _auto_off = millis() + AUTO_OFF_MILLIS; clearMsgPreview(); _node_name = node_name; - _build_date = build_date; _pin_code = pin_code; if (_display != NULL) { _display->turnOn(); } + + // strip off dash and commit hash by changing dash to null terminator + // e.g: v1.2.3-abcdef -> v1.2.3 + char *version = strdup(firmware_version); + char *dash = strchr(version, '-'); + if(dash){ + *dash = 0; + } + + #ifdef PIN_USER_BTN + pinMode(PIN_USER_BTN, INPUT); + #endif + + // v1.2.3 (1 Jan 2025) + sprintf(_version_info, "%s (%s)", version, build_date); } void UITask::msgRead(int msgcount) { @@ -47,6 +61,7 @@ void UITask::msgRead(int msgcount) { void UITask::clearMsgPreview() { _origin[0] = 0; _msg[0] = 0; + _need_refresh = true; } void UITask::newMsg(uint8_t path_len, const char* from_name, const char* text, int msgcount) { @@ -62,6 +77,7 @@ void UITask::newMsg(uint8_t path_len, const char* from_name, const char* text, i if (_display != NULL) { if (!_display->isOn()) _display->turnOn(); _auto_off = millis() + AUTO_OFF_MILLIS; // extend the auto-off timer + _need_refresh = true; } } @@ -73,38 +89,46 @@ void UITask::renderCurrScreen() { // render message preview _display->setCursor(0, 0); _display->setTextSize(1); + _display->setColor(DisplayDriver::GREEN); _display->print(_node_name); _display->setCursor(0, 12); + _display->setColor(DisplayDriver::YELLOW); _display->print(_origin); _display->setCursor(0, 24); + _display->setColor(DisplayDriver::LIGHT); _display->print(_msg); - _display->setCursor(100, 9); + _display->setCursor(_display->width() - 28, 9); _display->setTextSize(2); + _display->setColor(DisplayDriver::ORANGE); sprintf(tmp, "%d", _msgcount); _display->print(tmp); } else { // render 'home' screen + _display->setColor(DisplayDriver::BLUE); _display->drawXbm(0, 0, meshcore_logo, 128, 13); _display->setCursor(0, 20); _display->setTextSize(1); - _display->print(_node_name); - sprintf(tmp, "Build: %s", _build_date); + _display->setColor(DisplayDriver::LIGHT); + _display->print(_node_name); + _display->setCursor(0, 32); - _display->print(tmp); + _display->print(_version_info); if (_connected) { //_display->printf("freq : %03.2f sf %d\n", _prefs.freq, _prefs.sf); //_display->printf("bw : %03.2f cr %d\n", _prefs.bw, _prefs.cr); } else if (_pin_code != 0) { + _display->setColor(DisplayDriver::RED); _display->setTextSize(2); _display->setCursor(0, 43); sprintf(tmp, "Pin:%d", _pin_code); _display->print(tmp); } } + _need_refresh = false; } void UITask::userLedHandler() { @@ -148,6 +172,7 @@ void UITask::buttonHandler() { clearMsgPreview(); } else { _display->turnOn(); + _need_refresh = true; } _auto_off = cur_time + AUTO_OFF_MILLIS; // extend auto-off timer } @@ -173,7 +198,7 @@ void UITask::loop() { userLedHandler(); if (_display != NULL && _display->isOn()) { - if (millis() >= _next_refresh) { + if (millis() >= _next_refresh && _need_refresh) { _display->startFrame(); renderCurrScreen(); _display->endFrame(); diff --git a/examples/companion_radio/UITask.h b/examples/companion_radio/UITask.h index a0c60186..9050bc42 100644 --- a/examples/companion_radio/UITask.h +++ b/examples/companion_radio/UITask.h @@ -11,10 +11,11 @@ class UITask { bool _connected; uint32_t _pin_code; const char* _node_name; - const char* _build_date; + char _version_info[32]; char _origin[62]; char _msg[80]; int _msgcount; + bool _need_refresh = true; void renderCurrScreen(); void buttonHandler(); @@ -26,7 +27,7 @@ public: _next_refresh = 0; _connected = false; } - void begin(DisplayDriver* display, const char* node_name, const char* build_date, uint32_t pin_code); + void begin(DisplayDriver* display, const char* node_name, const char* build_date, const char* firmware_version, uint32_t pin_code); void setHasConnection(bool connected) { _connected = connected; } bool hasDisplay() const { return _display != NULL; } diff --git a/examples/companion_radio/main.cpp b/examples/companion_radio/main.cpp index e2640543..895a1bab 100644 --- a/examples/companion_radio/main.cpp +++ b/examples/companion_radio/main.cpp @@ -59,9 +59,14 @@ #ifdef DISPLAY_CLASS #include "UITask.h" - #include - - static DISPLAY_CLASS display; + #ifdef ST7789 + #include + #elif defined(HAS_GxEPD) + #include + #else + #include + #endif + static DISPLAY_CLASS display; #define HAS_UI #endif @@ -83,14 +88,14 @@ static uint32_t _atoi(const char* sp) { /*------------ Frame Protocol --------------*/ -#define FIRMWARE_VER_CODE 3 +#define FIRMWARE_VER_CODE 4 #ifndef FIRMWARE_BUILD_DATE - #define FIRMWARE_BUILD_DATE "7 Apr 2025" + #define FIRMWARE_BUILD_DATE "21 Apr 2025" #endif #ifndef FIRMWARE_VERSION - #define FIRMWARE_VERSION "v1.4.3" + #define FIRMWARE_VERSION "v1.5.0" #endif #define CMD_APP_START 1 @@ -130,6 +135,7 @@ static uint32_t _atoi(const char* sp) { #define CMD_SIGN_FINISH 35 #define CMD_SEND_TRACE_PATH 36 #define CMD_SET_DEVICE_PIN 37 +#define CMD_SET_OTHER_PARAMS 38 #define RESP_CODE_OK 0 #define RESP_CODE_ERR 1 @@ -164,6 +170,7 @@ static uint32_t _atoi(const char* sp) { #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 ERR_CODE_UNSUPPORTED_CMD 1 #define ERR_CODE_NOT_FOUND 2 @@ -184,7 +191,7 @@ struct NodePrefs { // persisted to file uint8_t sf; uint8_t cr; uint8_t reserved1; - uint8_t reserved2; + uint8_t manual_add_contacts; float bw; uint8_t tx_power_dbm; uint8_t unused[3]; @@ -499,11 +506,19 @@ protected: } } + bool isAutoAddEnabled() const override { + return (_prefs.manual_add_contacts & 1) == 0; + } + void onDiscoveredContact(ContactInfo& contact, bool is_new) override { if (_serial->isConnected()) { - 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); + 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 { soundBuzzer(); } @@ -663,6 +678,10 @@ protected: } 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); @@ -746,7 +765,7 @@ public: 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.reserved2, sizeof(_prefs.reserved2)); // 63 + 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.unused, sizeof(_prefs.unused)); // 69 @@ -847,7 +866,7 @@ public: 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.reserved2, sizeof(_prefs.reserved2)); // 63 + 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.unused, sizeof(_prefs.unused)); // 69 @@ -888,12 +907,15 @@ public: 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, alt = 0; + int32_t lat, lon; lat = (_prefs.node_lat * 1000000.0); lon = (_prefs.node_lon * 1000000.0); memcpy(&out_frame[i], &lat, 4); i += 4; memcpy(&out_frame[i], &lon, 4); i += 4; - memcpy(&out_frame[i], &alt, 4); i += 4; + out_frame[i++] = 0; // reserved + out_frame[i++] = 0; // reserved + out_frame[i++] = 0; // reserved + out_frame[i++] = _prefs.manual_add_contacts; uint32_t freq = _prefs.freq * 1000; memcpy(&out_frame[i], &freq, 4); i += 4; @@ -1177,6 +1199,10 @@ public: _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]; + savePrefs(); + writeOKFrame(); } else if (cmd_frame[0] == CMD_REBOOT && memcmp(&cmd_frame[1], "reboot", 6) == 0) { board.reboot(); } else if (cmd_frame[0] == CMD_GET_BATTERY_VOLTAGE) { @@ -1505,7 +1531,7 @@ void setup() { #endif #ifdef HAS_UI - ui_task.begin(disp, the_mesh.getNodeName(), FIRMWARE_BUILD_DATE, the_mesh.getBLEPin()); + ui_task.begin(disp, the_mesh.getNodeName(), FIRMWARE_BUILD_DATE, FIRMWARE_VERSION, the_mesh.getBLEPin()); #endif } diff --git a/examples/simple_repeater/UITask.cpp b/examples/simple_repeater/UITask.cpp index e8a204e3..6fff675e 100644 --- a/examples/simple_repeater/UITask.cpp +++ b/examples/simple_repeater/UITask.cpp @@ -20,25 +20,33 @@ static const uint8_t meshcore_logo [] PROGMEM = { 0xe3, 0xe3, 0x8f, 0xff, 0x1f, 0xfc, 0x3c, 0x0e, 0x1f, 0xf8, 0xff, 0xf8, 0x70, 0x3c, 0x7f, 0xf8, }; -void UITask::begin(const char* node_name, const char* build_date) { +void UITask::begin(const char* node_name, const char* build_date, const char* firmware_version) { _prevBtnState = HIGH; _auto_off = millis() + AUTO_OFF_MILLIS; _node_name = node_name; - _build_date = build_date; _display->turnOn(); + + // strip off dash and commit hash by changing dash to null terminator + // e.g: v1.2.3-abcdef -> v1.2.3 + char *version = strdup(firmware_version); + char *dash = strchr(version, '-'); + if(dash){ + *dash = 0; + } + + // v1.2.3 (1 Jan 2025) + sprintf(_version_info, "%s (%s)", version, build_date); } void UITask::renderCurrScreen() { - char tmp[80]; // render 'home' screen _display->drawXbm(0, 0, meshcore_logo, 128, 13); _display->setCursor(0, 20); _display->setTextSize(1); _display->print(_node_name); - sprintf(tmp, "Build: %s", _build_date); _display->setCursor(0, 32); - _display->print(tmp); + _display->print(_version_info); _display->setCursor(0, 43); _display->print("< Repeater >"); //_display->printf("freq : %03.2f sf %d\n", _prefs.freq, _prefs.sf); diff --git a/examples/simple_repeater/UITask.h b/examples/simple_repeater/UITask.h index e58d6111..13005957 100644 --- a/examples/simple_repeater/UITask.h +++ b/examples/simple_repeater/UITask.h @@ -7,12 +7,12 @@ class UITask { unsigned long _next_read, _next_refresh, _auto_off; int _prevBtnState; const char* _node_name; - const char* _build_date; + char _version_info[32]; void renderCurrScreen(); public: UITask(DisplayDriver& display) : _display(&display) { _next_read = _next_refresh = 0; } - void begin(const char* node_name, const char* build_date); + void begin(const char* node_name, const char* build_date, const char* firmware_version); void loop(); }; \ No newline at end of file diff --git a/examples/simple_repeater/main.cpp b/examples/simple_repeater/main.cpp index 79194e96..d08fec4a 100644 --- a/examples/simple_repeater/main.cpp +++ b/examples/simple_repeater/main.cpp @@ -20,11 +20,11 @@ /* ------------------------------ Config -------------------------------- */ #ifndef FIRMWARE_BUILD_DATE - #define FIRMWARE_BUILD_DATE "7 Apr 2025" + #define FIRMWARE_BUILD_DATE "21 Apr 2025" #endif #ifndef FIRMWARE_VERSION - #define FIRMWARE_VERSION "v1.4.3" + #define FIRMWARE_VERSION "v1.5.0" #endif #ifndef LORA_FREQ @@ -658,7 +658,7 @@ void setup() { the_mesh.begin(fs); #ifdef DISPLAY_CLASS - ui_task.begin(the_mesh.getNodeName(), FIRMWARE_BUILD_DATE); + ui_task.begin(the_mesh.getNodeName(), FIRMWARE_BUILD_DATE, FIRMWARE_VERSION); #endif // send out initial Advertisement to the mesh diff --git a/examples/simple_room_server/UITask.cpp b/examples/simple_room_server/UITask.cpp index 2f1d8ae5..eb7be78e 100644 --- a/examples/simple_room_server/UITask.cpp +++ b/examples/simple_room_server/UITask.cpp @@ -20,25 +20,33 @@ static const uint8_t meshcore_logo [] PROGMEM = { 0xe3, 0xe3, 0x8f, 0xff, 0x1f, 0xfc, 0x3c, 0x0e, 0x1f, 0xf8, 0xff, 0xf8, 0x70, 0x3c, 0x7f, 0xf8, }; -void UITask::begin(const char* node_name, const char* build_date) { +void UITask::begin(const char* node_name, const char* build_date, const char* firmware_version) { _prevBtnState = HIGH; _auto_off = millis() + AUTO_OFF_MILLIS; _node_name = node_name; - _build_date = build_date; _display->turnOn(); + + // strip off dash and commit hash by changing dash to null terminator + // e.g: v1.2.3-abcdef -> v1.2.3 + char *version = strdup(firmware_version); + char *dash = strchr(version, '-'); + if(dash){ + *dash = 0; + } + + // v1.2.3 (1 Jan 2025) + sprintf(_version_info, "%s (%s)", version, build_date); } void UITask::renderCurrScreen() { - char tmp[80]; // render 'home' screen _display->drawXbm(0, 0, meshcore_logo, 128, 13); _display->setCursor(0, 20); _display->setTextSize(1); _display->print(_node_name); - sprintf(tmp, "Build: %s", _build_date); _display->setCursor(0, 32); - _display->print(tmp); + _display->print(_version_info); _display->setCursor(0, 43); _display->print("< Room Server >"); //_display->printf("freq : %03.2f sf %d\n", _prefs.freq, _prefs.sf); diff --git a/examples/simple_room_server/UITask.h b/examples/simple_room_server/UITask.h index e58d6111..13005957 100644 --- a/examples/simple_room_server/UITask.h +++ b/examples/simple_room_server/UITask.h @@ -7,12 +7,12 @@ class UITask { unsigned long _next_read, _next_refresh, _auto_off; int _prevBtnState; const char* _node_name; - const char* _build_date; + char _version_info[32]; void renderCurrScreen(); public: UITask(DisplayDriver& display) : _display(&display) { _next_read = _next_refresh = 0; } - void begin(const char* node_name, const char* build_date); + void begin(const char* node_name, const char* build_date, const char* firmware_version); void loop(); }; \ No newline at end of file diff --git a/examples/simple_room_server/main.cpp b/examples/simple_room_server/main.cpp index 405c8f7f..931ad68d 100644 --- a/examples/simple_room_server/main.cpp +++ b/examples/simple_room_server/main.cpp @@ -20,11 +20,11 @@ /* ------------------------------ Config -------------------------------- */ #ifndef FIRMWARE_BUILD_DATE - #define FIRMWARE_BUILD_DATE "7 Apr 2025" + #define FIRMWARE_BUILD_DATE "21 Apr 2025" #endif #ifndef FIRMWARE_VERSION - #define FIRMWARE_VERSION "v1.4.3" + #define FIRMWARE_VERSION "v1.5.0" #endif #ifndef LORA_FREQ @@ -232,6 +232,17 @@ class MyMesh : public mesh::Mesh, public CommonCLICallbacks { } } + uint8_t getUnsyncedCount(ClientInfo* client) { + uint8_t count = 0; + for (int k = 0; k < MAX_UNSYNCED_POSTS; k++) { + if (posts[k].post_timestamp > client->sync_since // is new post for this Client? + && !posts[k].author.matches(client->id)) { // don't push posts to the author + count++; + } + } + return count; + } + bool processAck(const uint8_t *data) { for (int i = 0; i < num_clients; i++) { auto client = &known_clients[i]; @@ -398,7 +409,7 @@ protected: reply_data[4] = RESP_SERVER_LOGIN_OK; reply_data[5] = (CLIENT_KEEP_ALIVE_SECS >> 4); // NEW: recommended keep-alive interval (secs / 16) reply_data[6] = (perm == RoomPermission::ADMIN ? 1 : (perm == RoomPermission::GUEST ? 0 : 2)); - reply_data[7] = 0; // FUTURE: reserved + reply_data[7] = getUnsyncedCount(client); // NEW memcpy(&reply_data[8], "OK", 2); // REVISIT: not really needed next_push = futureMillis(PUSH_NOTIFY_DELAY_MILLIS); // delay next push, give RESPONSE packet time to arrive first @@ -572,6 +583,7 @@ protected: auto reply = createAck(ack_hash); if (reply) { + reply->payload[reply->payload_len++] = getUnsyncedCount(client); // NEW: add unsynced counter to end of ACK packet sendDirect(reply, client->out_path, client->out_path_len); } } @@ -887,7 +899,7 @@ void setup() { the_mesh.begin(fs); #ifdef DISPLAY_CLASS - ui_task.begin(the_mesh.getNodeName(), FIRMWARE_BUILD_DATE); + ui_task.begin(the_mesh.getNodeName(), FIRMWARE_BUILD_DATE, FIRMWARE_VERSION); #endif // send out initial Advertisement to the mesh diff --git a/platformio.ini b/platformio.ini index 1652f1e3..985943c7 100644 --- a/platformio.ini +++ b/platformio.ini @@ -59,4 +59,4 @@ build_flags = ${nrf52_base.build_flags} lib_deps = ${nrf52_base.lib_deps} rweather/Crypto @ ^0.4.0 - https://github.com/adafruit/Adafruit_nRF52_Arduino + https://github.com/adafruit/Adafruit_nRF52_Arduino \ No newline at end of file diff --git a/src/Dispatcher.cpp b/src/Dispatcher.cpp index ae225d36..7a415f07 100644 --- a/src/Dispatcher.cpp +++ b/src/Dispatcher.cpp @@ -101,6 +101,12 @@ void Dispatcher::checkRecv() { #endif pkt->header = raw[i++]; + if (pkt->hasTransportCodes()) { + memcpy(&pkt->transport_codes[0], &raw[i], 2); i += 2; + memcpy(&pkt->transport_codes[1], &raw[i], 2); i += 2; + } else { + pkt->transport_codes[0] = pkt->transport_codes[1] = 0; + } pkt->path_len = raw[i++]; if (pkt->path_len > MAX_PATH_SIZE || i + pkt->path_len > len) { @@ -132,7 +138,7 @@ void Dispatcher::checkRecv() { #if MESH_PACKET_LOGGING Serial.print(getLogDateTime()); Serial.printf(": RX, len=%d (type=%d, route=%s, payload_len=%d) SNR=%d RSSI=%d score=%d", - 2 + pkt->path_len + pkt->payload_len, pkt->getPayloadType(), pkt->isRouteDirect() ? "D" : "F", pkt->payload_len, + pkt->getRawLength(), pkt->getPayloadType(), pkt->isRouteDirect() ? "D" : "F", pkt->payload_len, (int)pkt->getSNR(), (int)_radio->getLastRSSI(), (int)(score*1000)); static uint8_t packet_hash[MAX_HASH_SIZE]; @@ -147,7 +153,7 @@ void Dispatcher::checkRecv() { Serial.printf("\n"); } #endif - logRx(pkt, 2 + pkt->path_len + pkt->payload_len, score); // hook for custom logging + logRx(pkt, pkt->getRawLength(), score); // hook for custom logging if (pkt->isRouteFlood()) { n_recv_flood++; @@ -212,6 +218,10 @@ void Dispatcher::checkSend() { raw[len++] = NODE_ID; #endif raw[len++] = outbound->header; + if (outbound->hasTransportCodes()) { + memcpy(&raw[len], &outbound->transport_codes[0], 2); len += 2; + memcpy(&raw[len], &outbound->transport_codes[1], 2); len += 2; + } raw[len++] = outbound->path_len; memcpy(&raw[len], outbound->path, outbound->path_len); len += outbound->path_len; diff --git a/src/Mesh.cpp b/src/Mesh.cpp index 0a0fd769..fe3b2473 100644 --- a/src/Mesh.cpp +++ b/src/Mesh.cpp @@ -15,7 +15,7 @@ bool Mesh::allowPacketForward(const mesh::Packet* packet) { return false; // by default, Transport NOT enabled } uint32_t Mesh::getRetransmitDelay(const mesh::Packet* packet) { - uint32_t t = (_radio->getEstAirtimeFor(packet->path_len + packet->payload_len + 2) * 52 / 50) / 2; + uint32_t t = (_radio->getEstAirtimeFor(packet->getRawLength()) * 52 / 50) / 2; return _rng->nextInt(0, 5)*t; } diff --git a/src/Packet.cpp b/src/Packet.cpp index e338b60d..cb31638c 100644 --- a/src/Packet.cpp +++ b/src/Packet.cpp @@ -10,6 +10,10 @@ Packet::Packet() { payload_len = 0; } +int Packet::getRawLength() const { + return 2 + path_len + payload_len + (hasTransportCodes() ? 4 : 0); +} + void Packet::calculatePacketHash(uint8_t* hash) const { SHA256 sha; uint8_t t = getPayloadType(); @@ -24,6 +28,10 @@ void Packet::calculatePacketHash(uint8_t* hash) const { uint8_t Packet::writeTo(uint8_t dest[]) const { uint8_t i = 0; dest[i++] = header; + if (hasTransportCodes()) { + memcpy(&dest[i], &transport_codes[0], 2); i += 2; + memcpy(&dest[i], &transport_codes[1], 2); i += 2; + } dest[i++] = path_len; memcpy(&dest[i], path, path_len); i += path_len; memcpy(&dest[i], payload, payload_len); i += payload_len; @@ -33,6 +41,12 @@ uint8_t Packet::writeTo(uint8_t dest[]) const { bool Packet::readFrom(const uint8_t src[], uint8_t len) { uint8_t i = 0; header = src[i++]; + if (hasTransportCodes()) { + memcpy(&transport_codes[0], &src[i], 2); i += 2; + memcpy(&transport_codes[1], &src[i], 2); i += 2; + } else { + transport_codes[0] = transport_codes[1] = 0; + } path_len = src[i++]; if (path_len > sizeof(path)) return false; // bad encoding memcpy(path, &src[i], path_len); i += path_len; diff --git a/src/Packet.h b/src/Packet.h index e20b3a49..7c7df8e3 100644 --- a/src/Packet.h +++ b/src/Packet.h @@ -11,10 +11,10 @@ namespace mesh { #define PH_VER_SHIFT 6 #define PH_VER_MASK 0x03 // 2-bits -#define ROUTE_TYPE_RESERVED1 0x00 // FUTURE -#define ROUTE_TYPE_FLOOD 0x01 // flood mode, needs 'path' to be built up (max 64 bytes) -#define ROUTE_TYPE_DIRECT 0x02 // direct route, 'path' is supplied -#define ROUTE_TYPE_RESERVED2 0x03 // FUTURE +#define ROUTE_TYPE_TRANSPORT_FLOOD 0x00 // flood mode + transport codes +#define ROUTE_TYPE_FLOOD 0x01 // flood mode, needs 'path' to be built up (max 64 bytes) +#define ROUTE_TYPE_DIRECT 0x02 // direct route, 'path' is supplied +#define ROUTE_TYPE_TRANSPORT_DIRECT 0x03 // direct route + transport codes #define PAYLOAD_TYPE_REQ 0x00 // request (prefixed with dest/src hashes, MAC) (enc data: timestamp, blob) #define PAYLOAD_TYPE_RESPONSE 0x01 // response to REQ or ANON_REQ (prefixed with dest/src hashes, MAC) (enc data: timestamp, blob) @@ -43,6 +43,7 @@ public: uint8_t header; uint16_t payload_len, path_len; + uint16_t transport_codes[2]; uint8_t path[MAX_PATH_SIZE]; uint8_t payload[MAX_PACKET_PAYLOAD]; int8_t _snr; @@ -58,8 +59,10 @@ public: */ uint8_t getRouteType() const { return header & PH_ROUTE_MASK; } - bool isRouteFlood() const { return getRouteType() == ROUTE_TYPE_FLOOD; } - bool isRouteDirect() const { return getRouteType() == ROUTE_TYPE_DIRECT; } + bool isRouteFlood() const { return getRouteType() == ROUTE_TYPE_FLOOD || getRouteType() == ROUTE_TYPE_TRANSPORT_FLOOD; } + bool isRouteDirect() const { return getRouteType() == ROUTE_TYPE_DIRECT || getRouteType() == ROUTE_TYPE_TRANSPORT_DIRECT; } + + bool hasTransportCodes() const { return getRouteType() == ROUTE_TYPE_TRANSPORT_FLOOD || getRouteType() == ROUTE_TYPE_TRANSPORT_DIRECT; } /** * \returns one of PAYLOAD_TYPE_ values @@ -76,6 +79,11 @@ public: float getSNR() const { return ((float)_snr) / 4.0f; } + /** + * \returns the encoded/wire format length of this packet + */ + int getRawLength() const; + /** * \brief save entire packet as a blob * \param dest (OUT) destination buffer (assumed to be MAX_MTU_SIZE) diff --git a/src/helpers/AutoDiscoverRTCClock.cpp b/src/helpers/AutoDiscoverRTCClock.cpp index e087744a..5c3a4f1c 100644 --- a/src/helpers/AutoDiscoverRTCClock.cpp +++ b/src/helpers/AutoDiscoverRTCClock.cpp @@ -8,8 +8,12 @@ static bool ds3231_success = false; static Melopero_RV3028 rtc_rv3028; static bool rv3028_success = false; +static RTC_PCF8563 rtc_8563; +static bool rtc_8563_success = false; + #define DS3231_ADDRESS 0x68 #define RV3028_ADDRESS 0x52 +#define PCF8563_ADDRESS 0x51 bool AutoDiscoverRTCClock::i2c_probe(TwoWire& wire, uint8_t addr) { wire.beginTransmission(addr); @@ -28,6 +32,9 @@ void AutoDiscoverRTCClock::begin(TwoWire& wire) { rtc_rv3028.set24HourMode(); // Set the device to use the 24hour format (default) instead of the 12 hour format rv3028_success = true; } + if(i2c_probe(wire,PCF8563_ADDRESS)){ + rtc_8563_success = rtc_8563.begin(&wire); + } } uint32_t AutoDiscoverRTCClock::getCurrentTime() { @@ -44,6 +51,9 @@ uint32_t AutoDiscoverRTCClock::getCurrentTime() { rtc_rv3028.getSecond() ).unixtime(); } + if(rtc_8563_success){ + return rtc_8563.now().unixtime(); + } return _fallback->getCurrentTime(); } @@ -52,9 +62,10 @@ void AutoDiscoverRTCClock::setCurrentTime(uint32_t time) { rtc_3231.adjust(DateTime(time)); } else if (rv3028_success) { auto dt = DateTime(time); - uint8_t weekday = (dt.day() + (uint16_t)((2.6 * dt.month()) - 0.2) - (2 * (dt.year() / 100)) + dt.year() + (uint16_t)(dt.year() / 4) + (uint16_t)(dt.year() / 400)) % 7; - + uint8_t weekday = (dt.day() + (uint16_t)((2.6 * dt.month()) - 0.2) - (2 * (dt.year() / 100)) + dt.year() + (uint16_t)(dt.year() / 4) + (uint16_t)(dt.year() / 400)) % 7; rtc_rv3028.setTime(dt.year(), dt.month(), weekday, dt.day(), dt.hour(), dt.minute(), dt.second()); + } else if (rtc_8563_success) { + rtc_8563.adjust(DateTime(time)); } else { _fallback->setCurrentTime(time); } diff --git a/src/helpers/BaseChatMesh.cpp b/src/helpers/BaseChatMesh.cpp index 083a0629..97aefff4 100644 --- a/src/helpers/BaseChatMesh.cpp +++ b/src/helpers/BaseChatMesh.cpp @@ -31,8 +31,29 @@ void BaseChatMesh::onAdvertRecv(mesh::Packet* packet, const mesh::Identity& id, } } + // save a copy of raw advert packet (to support "Share..." function) + int plen = packet->writeTo(temp_buf); + putBlobByKey(id.pub_key, PUB_KEY_SIZE, temp_buf, plen); + bool is_new = false; if (from == NULL) { + if (!isAutoAddEnabled()) { + ContactInfo ci; + memset(&ci, 0, sizeof(ci)); + ci.id = id; + ci.out_path_len = -1; // initially out_path is unknown + StrHelper::strncpy(ci.name, parser.getName(), sizeof(ci.name)); + ci.type = parser.getType(); + if (parser.hasLatLon()) { + ci.gps_lat = parser.getIntLat(); + ci.gps_lon = parser.getIntLon(); + } + ci.last_advert_timestamp = timestamp; + ci.lastmod = getRTCClock()->getCurrentTime(); + onDiscoveredContact(ci, true); // let UI know + return; + } + is_new = true; if (num_contacts < MAX_CONTACTS) { from = &contacts[num_contacts++]; @@ -50,10 +71,6 @@ void BaseChatMesh::onAdvertRecv(mesh::Packet* packet, const mesh::Identity& id, } } - // save a copy of raw advert packet (to support "Share..." function) - int plen = packet->writeTo(temp_buf); - putBlobByKey(id.pub_key, PUB_KEY_SIZE, temp_buf, plen); - // update StrHelper::strncpy(from->name, parser.getName(), sizeof(from->name)); from->type = parser.getType(); @@ -252,7 +269,7 @@ int BaseChatMesh::sendMessage(const ContactInfo& recipient, uint32_t timestamp, mesh::Packet* pkt = composeMsgPacket(recipient, timestamp, attempt, text, expected_ack); if (pkt == NULL) return MSG_SEND_FAILED; - uint32_t t = _radio->getEstAirtimeFor(pkt->payload_len + pkt->path_len + 2); + uint32_t t = _radio->getEstAirtimeFor(pkt->getRawLength()); int rc; if (recipient.out_path_len < 0) { @@ -279,7 +296,7 @@ int BaseChatMesh::sendCommandData(const ContactInfo& recipient, uint32_t timest auto pkt = createDatagram(PAYLOAD_TYPE_TXT_MSG, recipient.id, recipient.shared_secret, temp, 5 + text_len); if (pkt == NULL) return MSG_SEND_FAILED; - uint32_t t = _radio->getEstAirtimeFor(pkt->payload_len + pkt->path_len + 2); + uint32_t t = _radio->getEstAirtimeFor(pkt->getRawLength()); int rc; if (recipient.out_path_len < 0) { sendFlood(pkt); @@ -362,7 +379,7 @@ int BaseChatMesh::sendLogin(const ContactInfo& recipient, const char* password, auto pkt = createAnonDatagram(PAYLOAD_TYPE_ANON_REQ, self_id, recipient.id, recipient.shared_secret, temp, tlen); if (pkt) { - uint32_t t = _radio->getEstAirtimeFor(pkt->payload_len + pkt->path_len + 2); + uint32_t t = _radio->getEstAirtimeFor(pkt->getRawLength()); if (recipient.out_path_len < 0) { sendFlood(pkt); est_timeout = calcFloodTimeoutMillisFor(t); @@ -386,7 +403,7 @@ int BaseChatMesh::sendStatusRequest(const ContactInfo& recipient, uint32_t& est auto pkt = createDatagram(PAYLOAD_TYPE_REQ, recipient.id, recipient.shared_secret, temp, sizeof(temp)); if (pkt) { - uint32_t t = _radio->getEstAirtimeFor(pkt->payload_len + pkt->path_len + 2); + uint32_t t = _radio->getEstAirtimeFor(pkt->getRawLength()); if (recipient.out_path_len < 0) { sendFlood(pkt); est_timeout = calcFloodTimeoutMillisFor(t); diff --git a/src/helpers/BaseChatMesh.h b/src/helpers/BaseChatMesh.h index 30598f6c..ed6e1c3a 100644 --- a/src/helpers/BaseChatMesh.h +++ b/src/helpers/BaseChatMesh.h @@ -103,6 +103,7 @@ protected: } // 'UI' concepts, for sub-classes to implement + virtual bool isAutoAddEnabled() const { return true; } virtual void onDiscoveredContact(ContactInfo& contact, bool is_new) = 0; virtual bool processAck(const uint8_t *data) = 0; virtual void onContactPathUpdated(const ContactInfo& contact) = 0; diff --git a/src/helpers/CustomLR1110Wrapper.h b/src/helpers/CustomLR1110Wrapper.h index fb3a4b91..3a96d3c2 100644 --- a/src/helpers/CustomLR1110Wrapper.h +++ b/src/helpers/CustomLR1110Wrapper.h @@ -27,4 +27,5 @@ public: float getLastRSSI() const override { return ((CustomLR1110 *)_radio)->getRSSI(); } float getLastSNR() const override { return ((CustomLR1110 *)_radio)->getSNR(); } + int16_t setRxBoostedGainMode(bool en) { return ((CustomLR1110 *)_radio)->setRxBoostedGainMode(en); }; }; diff --git a/src/helpers/TBeamBoard.h b/src/helpers/TBeamBoard.h index 6c6367fa..fc52e712 100644 --- a/src/helpers/TBeamBoard.h +++ b/src/helpers/TBeamBoard.h @@ -33,11 +33,11 @@ class TBeamBoard : public ESP32Board { public: void begin() { ESP32Board::begin(); - + power.setALDO2Voltage(3300); power.enableALDO2(); - pinMode(38,INPUT_PULLUP); + pinMode(38, INPUT_PULLUP); esp_reset_reason_t reason = esp_reset_reason(); if (reason == ESP_RST_DEEPSLEEP) { @@ -75,7 +75,7 @@ public: } uint16_t getBattMilliVolts() override { - return 0; + return power.getBattVoltage(); } const char* getManufacturerName() const override { diff --git a/src/helpers/TBeamS3SupremeBoard.h b/src/helpers/TBeamS3SupremeBoard.h new file mode 100644 index 00000000..2b8232d8 --- /dev/null +++ b/src/helpers/TBeamS3SupremeBoard.h @@ -0,0 +1,106 @@ +#pragma once + +#include "ESP32Board.h" +#include +#include +#include +#include "XPowersLib.h" + +// LoRa radio module pins for TBeam S3 Supreme +#define P_LORA_DIO_1 1 //SX1262 IRQ pin +#define P_LORA_NSS 10 //SX1262 SS pin +#define P_LORA_RESET 5 //SX1262 Rest pin +#define P_LORA_BUSY 4 //SX1262 Busy pin +#define P_LORA_SCLK 12 //SX1262 SCLK pin +#define P_LORA_MISO 13 //SX1262 MISO pin +#define P_LORA_MOSI 11 //SX1262 MOSI pin + +#define PIN_BOARD_SDA 17 //SDA for OLED, BME280, and QMC6310U (0x1C) +#define PIN_BOARD_SCL 18 //SCL for OLED, BME280, and QMC6310U (0x1C) + +#define PIN_BOARD_SDA1 42 //SDA for PMU and PFC8563 (RTC) +#define PIN_BOARD_SCL1 41 //SCL for PMU and PFC8563 (RTC) +#define PIN_PMU_IRQ 40 //IRQ pin for PMU + +#define PIN_USER_BTN 0 + +#define P_BOARD_SPI_MOSI 35 //SPI for SD Card and QMI8653 (IMU) +#define P_BOARD_SPI_MISO 37 //SPI for SD Card and QMI8653 (IMU) +#define P_BOARD_SPI_SCK 36 //SPI for SD Card and QMI8653 (IMU) +#define P_BPARD_SPI_CS 47 //SPI for SD Card and QMI8653 (IMU) +#define P_BOARD_IMU_CS 34 //Pin for QMI8653 (IMU) CS + +#define P_BOARD_IMU_INT 33 //IMU Int pin +#define P_BOARD_RTC_INT 14 //RTC Int pin + +#define P_GPS_RX 9 //GPS RX pin +#define P_GPS_TX 8 //GPS TX pin +#define P_GPS_WAKE 7 //GPS Wakeup pin +#define P_GPS_1PPS 6 //GPS 1PPS pin + +//I2C Wire addresses +#define I2C_BME280_ADD 0x76 //BME280 sensor I2C address on Wire +#define I2C_OLED_ADD 0x3C //SH1106 OLED I2C address on Wire +#define I2C_QMC6310U_ADD 0x1C //QMC6310U mag sensor I2C address on Wire + +//I2C Wire1 addresses +#define I2C_RTC_ADD 0x51 //RTC I2C address on Wire1 +#define I2C_PMU_ADD 0x34 //AXP2101 I2C address on Wire1 + + + +class TBeamS3SupremeBoard : public ESP32Board { + +public: + void begin() { + + bool power_init(); + + ESP32Board::begin(); + + esp_reset_reason_t reason = esp_reset_reason(); + if (reason == ESP_RST_DEEPSLEEP) { + long wakeup_source = esp_sleep_get_ext1_wakeup_status(); + if (wakeup_source & (1 << P_LORA_DIO_1)) { // received a LoRa packet (while in deep sleep) + startup_reason = BD_STARTUP_RX_PACKET; + } + + rtc_gpio_hold_dis((gpio_num_t)P_LORA_NSS); + rtc_gpio_deinit((gpio_num_t)P_LORA_DIO_1); + } + } + + void enterDeepSleep(uint32_t secs, int pin_wake_btn = -1) { + esp_sleep_pd_config(ESP_PD_DOMAIN_RTC_PERIPH, ESP_PD_OPTION_ON); + + // Make sure the DIO1 and NSS GPIOs are hold on required levels during deep sleep + rtc_gpio_set_direction((gpio_num_t)P_LORA_DIO_1, RTC_GPIO_MODE_INPUT_ONLY); + rtc_gpio_pulldown_en((gpio_num_t)P_LORA_DIO_1); + + rtc_gpio_hold_en((gpio_num_t)P_LORA_NSS); + + if (pin_wake_btn < 0) { + esp_sleep_enable_ext1_wakeup( (1L << P_LORA_DIO_1), ESP_EXT1_WAKEUP_ANY_HIGH); // wake up on: recv LoRa packet + } else { + esp_sleep_enable_ext1_wakeup( (1L << P_LORA_DIO_1) | (1L << pin_wake_btn), ESP_EXT1_WAKEUP_ANY_HIGH); // wake up on: recv LoRa packet OR wake btn + } + + if (secs > 0) { + esp_sleep_enable_timer_wakeup(secs * 1000000); + } + + // Finally set ESP32 into sleep + esp_deep_sleep_start(); // CPU halts here and never returns! + } + + uint16_t getBattMilliVolts() override { + + return 0; + } + + uint16_t getBattPercent(); + + const char* getManufacturerName() const override { + return "LilyGo T-Beam S3 Supreme SX1262"; + } +}; diff --git a/src/helpers/nrf52/PromicroBoard.cpp b/src/helpers/nrf52/PromicroBoard.cpp index 58710509..b923e16e 100644 --- a/src/helpers/nrf52/PromicroBoard.cpp +++ b/src/helpers/nrf52/PromicroBoard.cpp @@ -14,7 +14,7 @@ void PromicroBoard::begin() { pinMode(PIN_VBAT_READ, INPUT); #ifdef BUTTON_PIN - pinMode(BUTTON_PIN, INPUT); + pinMode(BUTTON_PIN, INPUT_PULLUP); #endif #if defined(PIN_BOARD_SDA) && defined(PIN_BOARD_SCL) diff --git a/src/helpers/nrf52/RAK4631Board.cpp b/src/helpers/nrf52/RAK4631Board.cpp index 4d2f0edf..8b368734 100644 --- a/src/helpers/nrf52/RAK4631Board.cpp +++ b/src/helpers/nrf52/RAK4631Board.cpp @@ -27,7 +27,7 @@ void RAK4631Board::begin() { #endif #if defined(PIN_BOARD_SDA) && defined(PIN_BOARD_SCL) - Wire.setPins(PIN_BOARD_SDA, PIN_BOARD_SCL) + Wire.setPins(PIN_BOARD_SDA, PIN_BOARD_SCL); #endif Wire.begin(); diff --git a/src/helpers/nrf52/T1000eBoard.cpp b/src/helpers/nrf52/T1000eBoard.cpp index c6fc27a9..a17711db 100644 --- a/src/helpers/nrf52/T1000eBoard.cpp +++ b/src/helpers/nrf52/T1000eBoard.cpp @@ -18,7 +18,7 @@ void T1000eBoard::begin() { #endif #if defined(PIN_BOARD_SDA) && defined(PIN_BOARD_SCL) - Wire.setPins(PIN_BOARD_SDA, PIN_BOARD_SCL) + Wire.setPins(PIN_BOARD_SDA, PIN_BOARD_SCL); #endif Wire.begin(); diff --git a/src/helpers/nrf52/T1000eBoard.h b/src/helpers/nrf52/T1000eBoard.h index d71c829b..24584757 100644 --- a/src/helpers/nrf52/T1000eBoard.h +++ b/src/helpers/nrf52/T1000eBoard.h @@ -29,9 +29,16 @@ public: uint16_t getBattMilliVolts() override { #ifdef BATTERY_PIN + #ifdef PIN_3V3_EN + digitalWrite(PIN_3V3_EN, HIGH); + #endif analogReference(AR_INTERNAL_3_0); analogReadResolution(12); + delay(10); float volts = (analogRead(BATTERY_PIN) * ADC_MULTIPLIER * AREF_VOLTAGE) / 4096; + #ifdef PIN_3V3_EN + digitalWrite(PIN_3V3_EN, LOW); + #endif analogReference(AR_DEFAULT); // put back to default analogReadResolution(10); diff --git a/src/helpers/nrf52/T114Board.cpp b/src/helpers/nrf52/T114Board.cpp index d39b3e71..1f8c5854 100644 --- a/src/helpers/nrf52/T114Board.cpp +++ b/src/helpers/nrf52/T114Board.cpp @@ -27,7 +27,7 @@ void T114Board::begin() { pinMode(PIN_VBAT_READ, INPUT); #if defined(PIN_BOARD_SDA) && defined(PIN_BOARD_SCL) - Wire.setPins(PIN_BOARD_SDA, PIN_BOARD_SCL) + Wire.setPins(PIN_BOARD_SDA, PIN_BOARD_SCL); #endif Wire.begin(); diff --git a/src/helpers/nrf52/TechoBoard.cpp b/src/helpers/nrf52/TechoBoard.cpp index 13a250e6..dee14688 100644 --- a/src/helpers/nrf52/TechoBoard.cpp +++ b/src/helpers/nrf52/TechoBoard.cpp @@ -24,19 +24,6 @@ void TechoBoard::begin() { // for future use, sub-classes SHOULD call this from their begin() startup_reason = BD_STARTUP_NORMAL; - delay(200); - pinMode(PIN_PWR_EN, OUTPUT); - digitalWrite(PIN_PWR_EN, HIGH); - pinMode(PIN_BUTTON1, INPUT_PULLUP); - pinMode(PIN_BUTTON2, INPUT_PULLUP); - pinMode(LED_RED, OUTPUT); - pinMode(LED_GREEN, OUTPUT); - pinMode(LED_BLUE, OUTPUT); - delay(200); - - pinMode(PIN_TXCO, OUTPUT); - digitalWrite(PIN_TXCO, HIGH); - Wire.begin(); pinMode(SX126X_POWER_EN, OUTPUT); diff --git a/src/helpers/nrf52/XiaoNrf52Board.cpp b/src/helpers/nrf52/XiaoNrf52Board.cpp new file mode 100644 index 00000000..c603b2af --- /dev/null +++ b/src/helpers/nrf52/XiaoNrf52Board.cpp @@ -0,0 +1,95 @@ +#ifdef XIAO_NRF52 + +#include +#include "XiaoNrf52Board.h" + +#include +#include + +static BLEDfu bledfu; + +static void connect_callback(uint16_t conn_handle) +{ + (void)conn_handle; + MESH_DEBUG_PRINTLN("BLE client connected"); +} + +static void disconnect_callback(uint16_t conn_handle, uint8_t reason) +{ + (void)conn_handle; + (void)reason; + + MESH_DEBUG_PRINTLN("BLE client disconnected"); +} + +void XiaoNrf52Board::begin() { + // for future use, sub-classes SHOULD call this from their begin() + startup_reason = BD_STARTUP_NORMAL; + + pinMode(PIN_VBAT, INPUT); + pinMode(VBAT_ENABLE, OUTPUT); + digitalWrite(VBAT_ENABLE, HIGH); + +#if defined(PIN_WIRE_SDA) && defined(PIN_WIRE_SCL) + Wire.setPins(PIN_WIRE_SDA, PIN_WIRE_SCL); +#endif + + Wire.begin(); + +#ifdef P_LORA_TX_LED + pinMode(P_LORA_TX_LED, OUTPUT); + digitalWrite(P_LORA_TX_LED, HIGH); +#endif + +// pinMode(SX126X_POWER_EN, OUTPUT); +// digitalWrite(SX126X_POWER_EN, HIGH); + delay(10); // give sx1262 some time to power up +} + +bool XiaoNrf52Board::startOTAUpdate(const char* id, char reply[]) { + // Config the peripheral connection with maximum bandwidth + // more SRAM required by SoftDevice + // Note: All config***() function must be called before begin() + Bluefruit.configPrphBandwidth(BANDWIDTH_MAX); + Bluefruit.configPrphConn(92, BLE_GAP_EVENT_LENGTH_MIN, 16, 16); + + Bluefruit.begin(1, 0); + // Set max power. Accepted values are: -40, -30, -20, -16, -12, -8, -4, 0, 4 + Bluefruit.setTxPower(4); + // Set the BLE device name + Bluefruit.setName("XIAO_NRF52_OTA"); + + Bluefruit.Periph.setConnectCallback(connect_callback); + Bluefruit.Periph.setDisconnectCallback(disconnect_callback); + + // To be consistent OTA DFU should be added first if it exists + bledfu.begin(); + + // Set up and start advertising + // Advertising packet + Bluefruit.Advertising.addFlags(BLE_GAP_ADV_FLAGS_LE_ONLY_GENERAL_DISC_MODE); + Bluefruit.Advertising.addTxPower(); + Bluefruit.Advertising.addName(); + + /* Start Advertising + - Enable auto advertising if disconnected + - Interval: fast mode = 20 ms, slow mode = 152.5 ms + - Timeout for fast mode is 30 seconds + - Start(timeout) with timeout = 0 will advertise forever (until connected) + + For recommended advertising interval + https://developer.apple.com/library/content/qa/qa1931/_index.html + */ + Bluefruit.Advertising.restartOnDisconnect(true); + Bluefruit.Advertising.setInterval(32, 244); // in unit of 0.625 ms + Bluefruit.Advertising.setFastTimeout(30); // number of seconds in fast mode + Bluefruit.Advertising.start(0); // 0 = Don't stop advertising after n seconds + + strcpy(reply, "OK - started"); + return true; + + + return false; +} + +#endif \ No newline at end of file diff --git a/src/helpers/nrf52/XiaoNrf52Board.h b/src/helpers/nrf52/XiaoNrf52Board.h new file mode 100644 index 00000000..386001a2 --- /dev/null +++ b/src/helpers/nrf52/XiaoNrf52Board.h @@ -0,0 +1,75 @@ +#pragma once + +#include +#include + +#ifdef XIAO_NRF52 + +// LoRa radio module pins for Seeed Xiao-nrf52 +#ifdef SX1262_XIAO_S3_VARIANT + #define P_LORA_DIO_1 D0 + #define P_LORA_BUSY D1 + #define P_LORA_RESET D2 + #define P_LORA_NSS D3 + #define LORA_TX_BOOST_PIN D4 +#else + #define P_LORA_DIO_1 D1 + #define P_LORA_BUSY D3 + #define P_LORA_RESET D2 + #define P_LORA_NSS D4 + #define LORA_TX_BOOST_PIN D5 +#endif +#define P_LORA_SCLK PIN_SPI_SCK +#define P_LORA_MISO PIN_SPI_MISO +#define P_LORA_MOSI PIN_SPI_MOSI +//#define SX126X_POWER_EN 37 + +#define SX126X_DIO2_AS_RF_SWITCH true +#define SX126X_DIO3_TCXO_VOLTAGE 1.8 + + +class XiaoNrf52Board : public mesh::MainBoard { +protected: + uint8_t startup_reason; + +public: + void begin(); + uint8_t getStartupReason() const override { return startup_reason; } + +#if defined(P_LORA_TX_LED) + void onBeforeTransmit() override { + digitalWrite(P_LORA_TX_LED, LOW); // turn TX LED on + } + void onAfterTransmit() override { + digitalWrite(P_LORA_TX_LED, HIGH); // turn TX LED off + } +#endif + + uint16_t getBattMilliVolts() override { + // Please read befor going further ;) + // https://wiki.seeedstudio.com/XIAO_BLE#q3-what-are-the-considerations-when-using-xiao-nrf52840-sense-for-battery-charging + + // We can't drive VBAT_ENABLE to HIGH as long + // as we don't know wether we are charging or not ... + // this is a 3mA loss (4/1500) + digitalWrite(VBAT_ENABLE, LOW); + int adcvalue = 0; + analogReadResolution(12); + analogReference(AR_INTERNAL_3_0); + delay(10); + adcvalue = analogRead(PIN_VBAT); + return (adcvalue * ADC_MULTIPLIER * AREF_VOLTAGE) / 4.096; + } + + const char* getManufacturerName() const override { + return "Seeed Xiao-nrf52"; + } + + void reboot() override { + NVIC_SystemReset(); + } + + bool startOTAUpdate(const char* id, char reply[]) override; +}; + +#endif \ No newline at end of file diff --git a/src/helpers/ui/DisplayDriver.h b/src/helpers/ui/DisplayDriver.h index 7086b807..57aed85c 100644 --- a/src/helpers/ui/DisplayDriver.h +++ b/src/helpers/ui/DisplayDriver.h @@ -7,7 +7,7 @@ class DisplayDriver { protected: DisplayDriver(int w, int h) { _w = w; _h = h; } public: - enum Color { DARK, LIGHT }; + enum Color { DARK=0, LIGHT, RED, GREEN, BLUE, YELLOW, ORANGE }; // on b/w screen, colors will be !=0 synonym of light int width() const { return _w; } int height() const { return _h; } diff --git a/src/helpers/ui/GxEPDDisplay.cpp b/src/helpers/ui/GxEPDDisplay.cpp new file mode 100644 index 00000000..e7b70b49 --- /dev/null +++ b/src/helpers/ui/GxEPDDisplay.cpp @@ -0,0 +1,99 @@ + +#include "GxEPDDisplay.h" + +bool GxEPDDisplay::begin() { + display.epd2.selectSPI(SPI1, SPISettings(4000000, MSBFIRST, SPI_MODE0)); + SPI1.begin(); + display.init(115200, true, 2, false); + display.setRotation(3); + #ifdef TECHO_ZOOM + display.setFont(&FreeMono9pt7b); + #endif + display.setPartialWindow(0, 0, display.width(), display.height()); + + display.fillScreen(GxEPD_WHITE); + display.display(true); + #if DISP_BACKLIGHT + pinMode(DISP_BACKLIGHT, OUTPUT); + #endif + _init = true; + return true; +} + +void GxEPDDisplay::turnOn() { + if (!_init) begin(); +#if DISP_BACKLIGHT + digitalWrite(DISP_BACKLIGHT, HIGH); + _isOn = true; +#endif +} + +void GxEPDDisplay::turnOff() { +#if DISP_BACKLIGHT + digitalWrite(DISP_BACKLIGHT, LOW); +#endif + _isOn = false; +} + +void GxEPDDisplay::clear() { + display.fillScreen(GxEPD_WHITE); + display.setTextColor(GxEPD_BLACK); +} + +void GxEPDDisplay::startFrame(Color bkg) { + display.fillScreen(GxEPD_WHITE); +} + +void GxEPDDisplay::setTextSize(int sz) { + display.setTextSize(sz); +} + +void GxEPDDisplay::setColor(Color c) { + display.setTextColor(GxEPD_BLACK); +} + +void GxEPDDisplay::setCursor(int x, int y) { +#ifdef TECHO_ZOOM + x = x + (x >> 1); + y = y + (y >> 1); +#endif + display.setCursor(x, (y+10)); +} + +void GxEPDDisplay::print(const char* str) { + display.print(str); +} + +void GxEPDDisplay::fillRect(int x, int y, int w, int h) { +#ifdef TECHO_ZOOM + x = x + (x >> 1); + y = y + (y >> 1); + w = w + (w >> 1); + h = h + (h >> 1); +#endif + display.fillRect(x, y, w, h, GxEPD_BLACK); +} + +void GxEPDDisplay::drawRect(int x, int y, int w, int h) { +#ifdef TECHO_ZOOM + x = x + (x >> 1); + y = y + (y >> 1); + w = w + (w >> 1); + h = h + (h >> 1); +#endif + display.drawRect(x, y, w, h, GxEPD_BLACK); +} + +void GxEPDDisplay::drawXbm(int x, int y, const uint8_t* bits, int w, int h) { +#ifdef TECHO_ZOOM + x = x + (x >> 1); + y = y + (y >> 1); + w = w + (w >> 1); + h = h + (h >> 1); +#endif + display.drawBitmap(x*1.5, (y*1.5) + 10, bits, w, h, GxEPD_BLACK); +} + +void GxEPDDisplay::endFrame() { + display.display(true); +} diff --git a/src/helpers/ui/GxEPDDisplay.h b/src/helpers/ui/GxEPDDisplay.h new file mode 100644 index 00000000..ecadc50c --- /dev/null +++ b/src/helpers/ui/GxEPDDisplay.h @@ -0,0 +1,51 @@ +#pragma once + +#include +#include + +#define ENABLE_GxEPD2_GFX 0 + +#include +#include +#include +#include +#include + +#define GxEPD2_DISPLAY_CLASS GxEPD2_BW +#define GxEPD2_DRIVER_CLASS GxEPD2_150_BN // DEPG0150BN 200x200, SSD1681, (FPC8101), TTGO T5 V2.4.1 + +#include // 1.54" b/w + +#include "DisplayDriver.h" + +//GxEPD2_BW display(GxEPD2_150_BN(DISP_CS, DISP_DC, DISP_RST, DISP_BUSY)); // DEPG0150BN 200x200, SSD1681, TTGO T5 V2.4.1 + + +class GxEPDDisplay : public DisplayDriver { + + GxEPD2_BW display; + bool _init = false; + bool _isOn = false; + +public: + // there is a margin in y... + GxEPDDisplay() : DisplayDriver(200, 200-10), display(GxEPD2_150_BN(DISP_CS, DISP_DC, DISP_RST, DISP_BUSY)) { + + } + + bool begin(); + + bool isOn() override {return _isOn;}; + void turnOn() override; + void turnOff() override; + void clear() override; + void startFrame(Color bkg = DARK) override; + void setTextSize(int sz) override; + void setColor(Color c) override; + void setCursor(int x, int y) override; + void print(const char* str) override; + void fillRect(int x, int y, int w, int h) override; + void drawRect(int x, int y, int w, int h) override; + void drawXbm(int x, int y, const uint8_t* bits, int w, int h) override; + void endFrame() override; +}; diff --git a/src/helpers/ui/SSD1306Display.cpp b/src/helpers/ui/SSD1306Display.cpp index 911dd6fa..55516378 100644 --- a/src/helpers/ui/SSD1306Display.cpp +++ b/src/helpers/ui/SSD1306Display.cpp @@ -38,7 +38,7 @@ void SSD1306Display::setTextSize(int sz) { } void SSD1306Display::setColor(Color c) { - _color = (c == LIGHT) ? SSD1306_WHITE : SSD1306_BLACK; + _color = (c != 0) ? SSD1306_WHITE : SSD1306_BLACK; display.setTextColor(_color); } diff --git a/src/helpers/ui/ST7789Display.cpp b/src/helpers/ui/ST7789Display.cpp new file mode 100644 index 00000000..8f04f872 --- /dev/null +++ b/src/helpers/ui/ST7789Display.cpp @@ -0,0 +1,117 @@ +#ifdef ST7789 + +#include "ST7789Display.h" + +bool ST7789Display::i2c_probe(TwoWire& wire, uint8_t addr) { + return true; +/* + wire.beginTransmission(addr); + uint8_t error = wire.endTransmission(); + return (error == 0); +*/ +} + +bool ST7789Display::begin() { + if(!_isOn) { + pinMode(PIN_TFT_VDD_CTL, OUTPUT); + pinMode(PIN_TFT_LEDA_CTL, OUTPUT); + digitalWrite(PIN_TFT_VDD_CTL, LOW); + digitalWrite(PIN_TFT_LEDA_CTL, LOW); + digitalWrite(PIN_TFT_RST, HIGH); + + display.init(135, 240); + display.setRotation(2); + display.setSPISpeed(40000000); + display.fillScreen(ST77XX_BLACK); + display.setTextColor(ST77XX_WHITE); + display.setTextSize(2); + display.cp437(true); // Use full 256 char 'Code Page 437' font + + _isOn = true; + } + return true; +} + +void ST7789Display::turnOn() { + ST7789Display::begin(); +} + +void ST7789Display::turnOff() { + digitalWrite(PIN_TFT_VDD_CTL, HIGH); + digitalWrite(PIN_TFT_LEDA_CTL, HIGH); + digitalWrite(PIN_TFT_RST, LOW); + // digitalWrite(PIN_TFT_VDD_CTL, LOW); + // digitalWrite(PIN_TFT_LEDA_CTL, LOW); + _isOn = false; +} + +void ST7789Display::clear() { + display.fillScreen(ST77XX_BLACK); +} + +void ST7789Display::startFrame(Color bkg) { + display.fillScreen(0x00); + display.setTextColor(ST77XX_WHITE); + display.setTextSize(2); + display.cp437(true); // Use full 256 char 'Code Page 437' font +} + +void ST7789Display::setTextSize(int sz) { + display.setTextSize(sz); +} + +void ST7789Display::setColor(Color c) { + switch (c) { + case DisplayDriver::DARK : + _color = ST77XX_BLACK; + break; + case DisplayDriver::LIGHT : + _color = ST77XX_WHITE; + break; + case DisplayDriver::RED : + _color = ST77XX_RED; + break; + case DisplayDriver::GREEN : + _color = ST77XX_GREEN; + break; + case DisplayDriver::BLUE : + _color = ST77XX_BLUE; + break; + case DisplayDriver::YELLOW : + _color = ST77XX_YELLOW; + break; + case DisplayDriver::ORANGE : + _color = ST77XX_ORANGE; + break; + default: + _color = ST77XX_WHITE; + break; + } + display.setTextColor(_color); +} + +void ST7789Display::setCursor(int x, int y) { + display.setCursor(x, y); +} + +void ST7789Display::print(const char* str) { + display.print(str); +} + +void ST7789Display::fillRect(int x, int y, int w, int h) { + display.fillRect(x, y, w, h, _color); +} + +void ST7789Display::drawRect(int x, int y, int w, int h) { + display.drawRect(x, y, w, h, _color); +} + +void ST7789Display::drawXbm(int x, int y, const uint8_t* bits, int w, int h) { + display.drawBitmap(x, y, bits, w, h, _color); +} + +void ST7789Display::endFrame() { + // display.display(); +} + +#endif \ No newline at end of file diff --git a/src/helpers/ui/ST7789Display.h b/src/helpers/ui/ST7789Display.h new file mode 100644 index 00000000..af319ef0 --- /dev/null +++ b/src/helpers/ui/ST7789Display.h @@ -0,0 +1,33 @@ +#pragma once + +#include "DisplayDriver.h" +#include +#include +#include +#include + +class ST7789Display : public DisplayDriver { + Adafruit_ST7789 display; + bool _isOn; + uint16_t _color; + + bool i2c_probe(TwoWire& wire, uint8_t addr); +public: + ST7789Display() : DisplayDriver(135, 240), display(&SPI1, PIN_TFT_CS, PIN_TFT_DC, PIN_TFT_RST) { _isOn = false; } +// ST7789Display() : DisplayDriver(135, 240), display(PIN_TFT_CS, PIN_TFT_DC, PIN_TFT_SDA, PIN_TFT_SCL, PIN_TFT_RST) { _isOn = false; } + bool begin(); + + bool isOn() override { return _isOn; } + void turnOn() override; + void turnOff() override; + void clear() override; + void startFrame(Color bkg = DARK) override; + void setTextSize(int sz) override; + void setColor(Color c) override; + void setCursor(int x, int y) override; + void print(const char* str) override; + void fillRect(int x, int y, int w, int h) override; + void drawRect(int x, int y, int w, int h) override; + void drawXbm(int x, int y, const uint8_t* bits, int w, int h) override; + void endFrame() override; +}; diff --git a/variants/heltec_v2/platformio.ini b/variants/heltec_v2/platformio.ini index b8235906..bb1a8038 100644 --- a/variants/heltec_v2/platformio.ini +++ b/variants/heltec_v2/platformio.ini @@ -32,7 +32,7 @@ build_flags = ; -D MESH_DEBUG=1 build_src_filter = ${Heltec_lora32_v2.build_src_filter} +<../examples/simple_repeater> - + + + lib_deps = ${Heltec_lora32_v2.lib_deps} ${esp32_ota.lib_deps} @@ -50,7 +50,7 @@ build_flags = ; -D MESH_PACKET_LOGGING=1 ; -D MESH_DEBUG=1 build_src_filter = ${Heltec_lora32_v2.build_src_filter} - + + + +<../examples/simple_room_server> lib_deps = ${Heltec_lora32_v2.lib_deps} @@ -81,7 +81,7 @@ build_flags = ; NOTE: DO NOT ENABLE --> -D MESH_DEBUG=1 build_src_filter = ${Heltec_lora32_v2.build_src_filter} + - + + + +<../examples/companion_radio> lib_deps = ${Heltec_lora32_v2.lib_deps} @@ -102,7 +102,7 @@ build_flags = ; -D MESH_DEBUG=1 build_src_filter = ${Heltec_lora32_v2.build_src_filter} + - + + + +<../examples/companion_radio> lib_deps = ${Heltec_lora32_v2.lib_deps} diff --git a/variants/heltec_v3/platformio.ini b/variants/heltec_v3/platformio.ini index 370ec8f2..49fa7434 100644 --- a/variants/heltec_v3/platformio.ini +++ b/variants/heltec_v3/platformio.ini @@ -34,7 +34,7 @@ build_flags = -D MESH_PACKET_LOGGING=1 ; -D MESH_DEBUG=1 build_src_filter = ${Heltec_lora32_v3.build_src_filter} - + + + +<../examples/simple_repeater> lib_deps = ${Heltec_lora32_v3.lib_deps} @@ -53,7 +53,7 @@ build_flags = ; -D MESH_PACKET_LOGGING=1 ; -D MESH_DEBUG=1 build_src_filter = ${Heltec_lora32_v3.build_src_filter} - + + + +<../examples/simple_room_server> lib_deps = ${Heltec_lora32_v3.lib_deps} @@ -85,7 +85,7 @@ build_flags = ; NOTE: DO NOT ENABLE --> -D MESH_PACKET_LOGGING=1 ; NOTE: DO NOT ENABLE --> -D MESH_DEBUG=1 build_src_filter = ${Heltec_lora32_v3.build_src_filter} - + + + +<../examples/companion_radio> lib_deps = ${Heltec_lora32_v3.lib_deps} @@ -105,7 +105,7 @@ build_flags = ; -D MESH_PACKET_LOGGING=1 ; -D MESH_DEBUG=1 build_src_filter = ${Heltec_lora32_v3.build_src_filter} - + + + + +<../examples/companion_radio> lib_deps = @@ -127,7 +127,7 @@ build_flags = ; -D MESH_PACKET_LOGGING=1 ; -D MESH_DEBUG=1 build_src_filter = ${Heltec_lora32_v3.build_src_filter} - + + + + +<../examples/companion_radio> lib_deps = diff --git a/variants/lilygo_t3s3/platformio.ini b/variants/lilygo_t3s3/platformio.ini index 43b8d16d..c857d51d 100644 --- a/variants/lilygo_t3s3/platformio.ini +++ b/variants/lilygo_t3s3/platformio.ini @@ -45,7 +45,7 @@ build_flags = ; -D MESH_PACKET_LOGGING=1 ; -D MESH_DEBUG=1 build_src_filter = ${LilyGo_T3S3_sx1262.build_src_filter} - + + + +<../examples/simple_repeater> lib_deps = ${LilyGo_T3S3_sx1262.lib_deps} @@ -78,7 +78,7 @@ build_flags = ; -D MESH_PACKET_LOGGING=1 ; -D MESH_DEBUG=1 build_src_filter = ${LilyGo_T3S3_sx1262.build_src_filter} - + + + +<../examples/simple_room_server> lib_deps = ${LilyGo_T3S3_sx1262.lib_deps} @@ -96,7 +96,7 @@ build_flags = ; NOTE: DO NOT ENABLE --> -D MESH_PACKET_LOGGING=1 ; NOTE: DO NOT ENABLE --> -D MESH_DEBUG=1 build_src_filter = ${LilyGo_T3S3_sx1262.build_src_filter} - + + + +<../examples/companion_radio> lib_deps = ${LilyGo_T3S3_sx1262.lib_deps} @@ -117,7 +117,7 @@ build_flags = ; -D MESH_DEBUG=1 build_src_filter = ${LilyGo_T3S3_sx1262.build_src_filter} + - + + + +<../examples/companion_radio> lib_deps = ${LilyGo_T3S3_sx1262.lib_deps} diff --git a/variants/lilygo_tbeam/platformio.ini b/variants/lilygo_tbeam/platformio.ini index 007d06d2..129d2d32 100644 --- a/variants/lilygo_tbeam/platformio.ini +++ b/variants/lilygo_tbeam/platformio.ini @@ -27,7 +27,7 @@ build_flags = ${LilyGo_TBeam.build_flags} -D DISPLAY_CLASS=SSD1306Display -D MAX_CONTACTS=100 - -D MAX_GROUP_CHANNELS=1 + -D MAX_GROUP_CHANNELS=8 -D BLE_PIN_CODE=123456 -D BLE_DEBUG_LOGGING=1 -D MESH_PACKET_LOGGING=1 @@ -39,7 +39,7 @@ build_flags = ; -D MESH_DEBUG=1 build_src_filter = ${LilyGo_TBeam.build_src_filter} + - + + + +<../examples/companion_radio> lib_deps = ${LilyGo_TBeam.lib_deps} @@ -57,7 +57,7 @@ build_flags = -D MESH_PACKET_LOGGING=1 ; -D MESH_DEBUG=1 build_src_filter = ${LilyGo_TBeam.build_src_filter} - + + + +<../examples/simple_repeater> lib_deps = ${LilyGo_TBeam.lib_deps} diff --git a/variants/lilygo_tbeam_supreme_SX1262/platformio.ini b/variants/lilygo_tbeam_supreme_SX1262/platformio.ini new file mode 100644 index 00000000..57cc68db --- /dev/null +++ b/variants/lilygo_tbeam_supreme_SX1262/platformio.ini @@ -0,0 +1,72 @@ +[T_Beam_S3_Supreme_SX1262] +extends = esp32_base +board = t_beams3_supreme ; LILYGO T-Beam Supreme ESP32S3 with SX1262 +build_flags = + ${esp32_base.build_flags} + -I variants/lilygo_tbeam_supreme_SX1262 + -D LORA_TX_POWER=22 + -D RADIO_CLASS=CustomSX1262 + -D WRAPPER_CLASS=CustomSX1262Wrapper + ;-D DISPLAY_CLASS=SSD1306Display ;Needs to be modified for SH1106 + -D SX126X_RX_BOOSTED_GAIN=1 +build_src_filter = ${esp32_base.build_src_filter} + +<../variants/lilygo_tbeam_supreme_SX1262> +board_build.partitions = min_spiffs.csv ; get around 4mb flash limit +lib_deps = + ${esp32_base.lib_deps} + lewisxhe/PCF8563_Library@^1.0.1 + lewisxhe/XPowersLib @ ^0.2.7 + ;adafruit/Adafruit SSD1306 @ ^2.5.13 + +; === LILYGO T-Beam S3 Supreme with SX1262 environments === +[env:T_Beam_S3_Supreme_SX1262_repeater] +extends = T_Beam_S3_Supreme_SX1262 +build_flags = + ${T_Beam_S3_Supreme_SX1262.build_flags} + -D ADVERT_NAME='"T-Beam S3 Supreme SX1262 Repeater"' + -D ADVERT_LAT=0 + -D ADVERT_LON=0 + -D ADMIN_PASSWORD='"password"' +; -D MESH_PACKET_LOGGING=1 +; -D MESH_DEBUG=1 +build_src_filter = ${T_Beam_S3_Supreme_SX1262.build_src_filter} + +<../examples/simple_repeater> +lib_deps = + ${T_Beam_S3_Supreme_SX1262.lib_deps} + ${esp32_ota.lib_deps} + +[env:T_Beam_S3_Supreme_SX1262_room_server] +extends = T_Beam_S3_Supreme_SX1262 +build_flags = + ${T_Beam_S3_Supreme_SX1262.build_flags} + -D ADVERT_NAME='"T_Beam_S3_Supreme_SX1262 Room"' + -D ADVERT_LAT=0.0 + -D ADVERT_LON=0.0 + -D ADMIN_PASSWORD='"password"' + -D ROOM_PASSWORD='"hello"' +; -D MESH_PACKET_LOGGING=1 +; -D MESH_DEBUG=1 +build_src_filter = ${T_Beam_S3_Supreme_SX1262.build_src_filter} + +<../examples/simple_room_server> +lib_deps = + ${T_Beam_S3_Supreme_SX1262.lib_deps} + ${esp32_ota.lib_deps} + +[env:T_Beam_S3_Supreme_SX1262_companion_radio_ble] +extends = T_Beam_S3_Supreme_SX1262 +build_flags = + ${T_Beam_S3_Supreme_SX1262.build_flags} + -D MAX_CONTACTS=100 + -D MAX_GROUP_CHANNELS=1 + -D BLE_PIN_CODE=123456 + -D BLE_DEBUG_LOGGING=1 +; -D ENABLE_PRIVATE_KEY_IMPORT=1 +; -D ENABLE_PRIVATE_KEY_EXPORT=1 + -D MESH_PACKET_LOGGING=8 + -D MESH_DEBUG=1 +build_src_filter = ${T_Beam_S3_Supreme_SX1262.build_src_filter} + + + +<../examples/companion_radio> +lib_deps = + ${T_Beam_S3_Supreme_SX1262.lib_deps} + densaugeo/base64 @ ~1.4.0 \ No newline at end of file diff --git a/variants/lilygo_tbeam_supreme_SX1262/target.cpp b/variants/lilygo_tbeam_supreme_SX1262/target.cpp new file mode 100644 index 00000000..c7ab2984 --- /dev/null +++ b/variants/lilygo_tbeam_supreme_SX1262/target.cpp @@ -0,0 +1,182 @@ +#include +#include "target.h" + +TBeamS3SupremeBoard board; + +// Using PMU AXP2102 +XPowersAXP2101 PMU; + +bool pmuIntFlag; + +#ifndef LORA_CR + #define LORA_CR 5 +#endif + +#if defined(P_LORA_SCLK) + static SPIClass spi; + RADIO_CLASS radio = new Module(P_LORA_NSS, P_LORA_DIO_1, P_LORA_RESET, P_LORA_BUSY, spi); +#else + RADIO_CLASS radio = new Module(P_LORA_NSS, P_LORA_DIO_1, P_LORA_RESET, P_LORA_BUSY); +#endif + +WRAPPER_CLASS radio_driver(radio, board); + +ESP32RTCClock fallback_clock; +AutoDiscoverRTCClock rtc_clock(fallback_clock); + + +static void setPMUIntFlag(){ + pmuIntFlag = true; +} + +bool power_init() { + //Start up Wire1 with PMU address + //Serial.println("Starting Wire1 for PMU"); + //Wire1.begin(I2C_PMU_ADD); + //Wire1.begin(PIN_BOARD_SDA1,PIN_BOARD_SCL1); + + //Set LED to indicate charge state + Serial.println("Setting charge led"); + PMU.setChargingLedMode(XPOWERS_CHG_LED_CTRL_CHG); + + //Set up PMU interrupts + Serial.println("Setting up PMU interrupts"); + pinMode(PIN_PMU_IRQ,INPUT_PULLUP); + attachInterrupt(PIN_PMU_IRQ,setPMUIntFlag,FALLING); + + //GPS + Serial.println("Setting and enabling a-ldo4 for GPS"); + PMU.setALDO4Voltage(3300); + PMU.enableALDO4(); //disable to save power + + //Lora + Serial.println("Setting and enabling a-ldo3 for LoRa"); + PMU.setALDO3Voltage(3300); + PMU.enableALDO3(); + + //To avoid SPI bus issues during power up, reset OLED, sensor, and SD card supplies + Serial.println("Reset a-ldo1&2 and b-ldo1"); + if(ESP_SLEEP_WAKEUP_UNDEFINED == esp_sleep_get_wakeup_cause()){ + PMU.enableALDO1(); + PMU.enableALDO2(); + PMU.enableBLDO1(); + delay(250); + } + + //BME280 and OLED + Serial.println("Setting and enabling a-ldo1 for oled"); + PMU.setALDO1Voltage(3300); + PMU.enableALDO1(); + + //QMC6310U + Serial.println("Setting and enabling a-ldo2 for QMC"); + PMU.setALDO2Voltage(3300); + PMU.enableALDO2(); //disable to save power + + //SD card + Serial.println("Setting and enabling b-ldo2 for SD card"); + PMU.setBLDO1Voltage(3300); + PMU.enableBLDO1(); + + //Out to header pins + Serial.println("Setting and enabling b-ldo2 for output to header"); + PMU.setBLDO2Voltage(3300); + PMU.enableBLDO2(); + + Serial.println("Setting and enabling dcdc4 for output to header"); + PMU.setDC4Voltage(XPOWERS_AXP2101_DCDC4_VOL2_MAX); //1.8V + PMU.enableDC4(); + + Serial.println("Setting and enabling dcdc5 for output to header"); + PMU.setDC5Voltage(3300); + PMU.enableDC5(); + + //Other power rails + Serial.println("Setting and enabling dcdc3 for ?"); + PMU.setDC3Voltage(3300); //doesn't go anywhere in the schematic?? + PMU.enableDC3(); + + //Unused power rails + Serial.println("Disabling unused supplies dcdc2, dldo1 and dldo2"); + PMU.disableDC2(); + PMU.disableDLDO1(); + PMU.disableDLDO2(); + + //Set charge current to 300mA + Serial.println("Setting battery charge current limit and voltage"); + PMU.setChargerConstantCurr(XPOWERS_AXP2101_CHG_CUR_300MA); + PMU.setChargeTargetVoltage(XPOWERS_AXP2101_CHG_VOL_4V2); + + //enable battery voltage measurement + Serial.println("Enabling battery measurement"); + PMU.enableBattVoltageMeasure(); + + //Reset and re-enable PMU interrupts + Serial.println("Re-enable interrupts"); + PMU.disableIRQ(XPOWERS_AXP2101_ALL_IRQ); + PMU.clearIrqStatus(); + PMU.enableIRQ( + XPOWERS_AXP2101_BAT_INSERT_IRQ | XPOWERS_AXP2101_BAT_REMOVE_IRQ | //Battery interrupts + XPOWERS_AXP2101_VBUS_INSERT_IRQ | XPOWERS_AXP2101_VBUS_REMOVE_IRQ | //VBUS interrupts + XPOWERS_AXP2101_PKEY_SHORT_IRQ | XPOWERS_AXP2101_PKEY_LONG_IRQ | //Power Key interrupts + XPOWERS_AXP2101_BAT_CHG_DONE_IRQ | XPOWERS_AXP2101_BAT_CHG_START_IRQ //Charging interrupts + ); + + //Set the power key off press time + PMU.setPowerKeyPressOffTime(XPOWERS_POWEROFF_4S); + + return true; +} + +bool radio_init() { + fallback_clock.begin(); + Wire1.begin(PIN_BOARD_SDA1,PIN_BOARD_SCL1); + rtc_clock.begin(Wire1); + +#ifdef SX126X_DIO3_TCXO_VOLTAGE + float tcxo = SX126X_DIO3_TCXO_VOLTAGE; +#else + float tcxo = 1.6f; +#endif + +#if defined(P_LORA_SCLK) + spi.begin(P_LORA_SCLK, P_LORA_MISO, P_LORA_MOSI); +#endif + int status = radio.begin(LORA_FREQ, LORA_BW, LORA_SF, LORA_CR, RADIOLIB_SX126X_SYNC_WORD_PRIVATE, LORA_TX_POWER, 8, tcxo); + if (status != RADIOLIB_ERR_NONE) { + Serial.print("ERROR: radio init failed: "); + Serial.println(status); + return false; // fail + } + + radio.setCRC(1); + + return true; // success +} + +uint16_t getBattPercent() { + //Read the PMU fuel guage for battery % + uint16_t battPercent = PMU.getBatteryPercent(); + + return battPercent; +} + +uint32_t radio_get_rng_seed() { + return radio.random(0x7FFFFFFF); +} + +void radio_set_params(float freq, float bw, uint8_t sf, uint8_t cr) { + radio.setFrequency(freq); + radio.setSpreadingFactor(sf); + radio.setBandwidth(bw); + radio.setCodingRate(cr); +} + +void radio_set_tx_power(uint8_t dbm) { + radio.setOutputPower(dbm); +} + +mesh::LocalIdentity radio_new_identity() { + RadioNoiseListener rng(radio); + return mesh::LocalIdentity(&rng); // create new random identity +} diff --git a/variants/lilygo_tbeam_supreme_SX1262/target.h b/variants/lilygo_tbeam_supreme_SX1262/target.h new file mode 100644 index 00000000..2ee3cb01 --- /dev/null +++ b/variants/lilygo_tbeam_supreme_SX1262/target.h @@ -0,0 +1,17 @@ +#pragma once + +#include +#include +#include +#include +#include + +extern TBeamS3SupremeBoard board; +extern WRAPPER_CLASS radio_driver; +extern AutoDiscoverRTCClock rtc_clock; + +bool radio_init(); +uint32_t radio_get_rng_seed(); +void radio_set_params(float freq, float bw, uint8_t sf, uint8_t cr); +void radio_set_tx_power(uint8_t dbm); +mesh::LocalIdentity radio_new_identity(); \ No newline at end of file diff --git a/variants/lilygo_tlora_v2_1/platformio.ini b/variants/lilygo_tlora_v2_1/platformio.ini index da183b2b..078efc9c 100644 --- a/variants/lilygo_tlora_v2_1/platformio.ini +++ b/variants/lilygo_tlora_v2_1/platformio.ini @@ -34,7 +34,7 @@ lib_deps = [env:LilyGo_TLora_V2_1_1_6_Repeater] extends = LilyGo_TLora_V2_1_1_6 build_src_filter = ${LilyGo_TLora_V2_1_1_6.build_src_filter} - + + + +<../examples/simple_repeater> build_flags = ${LilyGo_TLora_V2_1_1_6.build_flags} @@ -58,7 +58,7 @@ build_flags = ; -D MESH_PACKET_LOGGING=1 ; -D MESH_DEBUG=1 build_src_filter = ${LilyGo_TLora_V2_1_1_6.build_src_filter} - + + + +<../examples/simple_repeater> lib_deps = ${LilyGo_TLora_V2_1_1_6.lib_deps} @@ -75,7 +75,7 @@ build_flags = ; NOTE: DO NOT ENABLE --> -D MESH_PACKET_LOGGING=1 ; NOTE: DO NOT ENABLE --> -D MESH_DEBUG=1 build_src_filter = ${LilyGo_TLora_V2_1_1_6.build_src_filter} - + + + +<../examples/companion_radio> lib_deps = ${LilyGo_TLora_V2_1_1_6.lib_deps} @@ -95,7 +95,7 @@ build_flags = ; -D MESH_DEBUG=1 build_src_filter = ${LilyGo_TLora_V2_1_1_6.build_src_filter} + - + + + +<../examples/companion_radio> lib_deps = ${LilyGo_TLora_V2_1_1_6.lib_deps} @@ -104,7 +104,7 @@ lib_deps = [env:LilyGo_TLora_V2_1_1_6_room_server] extends = LilyGo_TLora_V2_1_1_6 build_src_filter = ${LilyGo_TLora_V2_1_1_6.build_src_filter} - + + + +<../examples/simple_room_server> build_flags = ${LilyGo_TLora_V2_1_1_6.build_flags} diff --git a/variants/rak4631/platformio.ini b/variants/rak4631/platformio.ini index 63d6b6b8..3f40447f 100644 --- a/variants/rak4631/platformio.ini +++ b/variants/rak4631/platformio.ini @@ -7,13 +7,16 @@ build_flags = ${nrf52840_base.build_flags} -I variants/rak4631 -D RAK_4631 -D PIN_USER_BTN=9 + -D PIN_BOARD_SCL=14 + -D PIN_BOARD_SDA=13 + -D PIN_OLED_RESET=-1 -D RADIO_CLASS=CustomSX1262 -D WRAPPER_CLASS=CustomSX1262Wrapper -D LORA_TX_POWER=22 -D SX126X_CURRENT_LIMIT=130 -D SX126X_RX_BOOSTED_GAIN=1 build_src_filter = ${nrf52840_base.build_src_filter} - + + + +<../variants/rak4631> lib_deps = ${nrf52840_base.lib_deps} @@ -31,7 +34,7 @@ build_flags = ; -D MESH_PACKET_LOGGING=1 ; -D MESH_DEBUG=1 build_src_filter = ${rak4631.build_src_filter} - + + + +<../examples/simple_repeater> [env:RAK_4631_room_server] @@ -47,7 +50,7 @@ build_flags = ; -D MESH_PACKET_LOGGING=1 ; -D MESH_DEBUG=1 build_src_filter = ${rak4631.build_src_filter} - + + + +<../examples/simple_room_server> [env:RAK_4631_companion_radio_usb] @@ -62,7 +65,7 @@ build_flags = ; NOTE: DO NOT ENABLE --> -D MESH_PACKET_LOGGING=1 ; NOTE: DO NOT ENABLE --> -D MESH_DEBUG=1 build_src_filter = ${rak4631.build_src_filter} - + + + +<../examples/companion_radio> lib_deps = ${rak4631.lib_deps} @@ -82,8 +85,8 @@ build_flags = ; -D MESH_PACKET_LOGGING=1 ; -D MESH_DEBUG=1 build_src_filter = ${rak4631.build_src_filter} - + - + + + + + +<../examples/companion_radio> lib_deps = ${rak4631.lib_deps} diff --git a/variants/t1000-e/variant.cpp b/variants/t1000-e/variant.cpp index a71a831b..f17b3a8d 100644 --- a/variants/t1000-e/variant.cpp +++ b/variants/t1000-e/variant.cpp @@ -83,13 +83,13 @@ void initVariant() pinMode(GPS_RTC_INT, OUTPUT); pinMode(LED_PIN, OUTPUT); - digitalWrite(PIN_3V3_EN, HIGH); + digitalWrite(PIN_3V3_EN, LOW); digitalWrite(PIN_3V3_ACC_EN, LOW); digitalWrite(BUZZER_EN, LOW); digitalWrite(SENSOR_EN, LOW); digitalWrite(GPS_EN, LOW); digitalWrite(GPS_RESET, LOW); - digitalWrite(GPS_VRTC_EN, HIGH); + digitalWrite(GPS_VRTC_EN, LOW); digitalWrite(GPS_SLEEP_INT, HIGH); digitalWrite(GPS_RTC_INT, LOW); digitalWrite(LED_PIN, LOW); diff --git a/variants/t114/platformio.ini b/variants/t114/platformio.ini index 297517d4..2abdfc69 100644 --- a/variants/t114/platformio.ini +++ b/variants/t114/platformio.ini @@ -74,3 +74,34 @@ build_src_filter = ${Heltec_t114.build_src_filter} lib_deps = ${Heltec_t114.lib_deps} densaugeo/base64 @ ~1.4.0 + +[env:Heltec_t114_companion_radio_ble_screen] +extends = env:Heltec_t114_companion_radio_ble +build_flags = ${env:Heltec_t114_companion_radio_ble.build_flags} + -I src/helpers/ui + -D ST7789 + -D DISPLAY_CLASS=ST7789Display +build_src_filter = ${env:Heltec_t114_companion_radio_ble.build_src_filter} + +<../examples/companion_radio/UITask.cpp> + + +lib_deps = ${env:Heltec_t114_companion_radio_ble.lib_deps} + adafruit/Adafruit ST7735 and ST7789 Library @ ^1.11.0 + +[env:Heltec_t114_companion_radio_usb] +extends = Heltec_t114 +build_flags = + ${Heltec_t114.build_flags} + -D MAX_CONTACTS=100 + -D MAX_GROUP_CHANNELS=8 +; -D BLE_PIN_CODE=123456 +; -D BLE_DEBUG_LOGGING=1 +; -D ENABLE_PRIVATE_KEY_IMPORT=1 +; -D ENABLE_PRIVATE_KEY_EXPORT=1 +; -D MESH_PACKET_LOGGING=1 +; -D MESH_DEBUG=1 +build_src_filter = ${Heltec_t114.build_src_filter} + + + +<../examples/companion_radio/main.cpp> +lib_deps = + ${Heltec_t114.lib_deps} + densaugeo/base64 @ ~1.4.0 \ No newline at end of file diff --git a/variants/t114/variant.h b/variants/t114/variant.h index ee04861e..56fc536d 100644 --- a/variants/t114/variant.h +++ b/variants/t114/variant.h @@ -80,11 +80,13 @@ //////////////////////////////////////////////////////////////////////////////// // Builtin buttons -#define PIN_BUTTON1 (5) +#define PIN_BUTTON1 (42) #define BUTTON_PIN PIN_BUTTON1 -#define PIN_BUTTON2 (11) -#define BUTTON_PIN2 PIN_BUTTON2 +// #define PIN_BUTTON2 (11) +// #define BUTTON_PIN2 PIN_BUTTON2 + +#define PIN_USER_BTN BUTTON_PIN #define EXTERNAL_FLASH_DEVICES MX25R1635F #define EXTERNAL_FLASH_USE_QSPI @@ -108,3 +110,14 @@ // Buzzer #define PIN_BUZZER (46) + + +//////////////////////////////////////////////////////////////////////////////// +// TFT +#define PIN_TFT_SCL (40) +#define PIN_TFT_SDA (41) +#define PIN_TFT_RST (2) +#define PIN_TFT_VDD_CTL (3) +#define PIN_TFT_LEDA_CTL (15) +#define PIN_TFT_CS (11) +#define PIN_TFT_DC (12) diff --git a/variants/techo/platformio.ini b/variants/techo/platformio.ini index 6b681fb4..f3c2f973 100644 --- a/variants/techo/platformio.ini +++ b/variants/techo/platformio.ini @@ -56,17 +56,23 @@ build_flags = extends = LilyGo_Techo build_flags = ${LilyGo_Techo.build_flags} + -I src/helpers/ui -D MAX_CONTACTS=100 -D MAX_GROUP_CHANNELS=8 -D BLE_PIN_CODE=123456 -D BLE_DEBUG_LOGGING=1 + -D DISPLAY_CLASS=GxEPDDisplay + -D HAS_GxEPD ; -D ENABLE_PRIVATE_KEY_IMPORT=1 ; -D ENABLE_PRIVATE_KEY_EXPORT=1 ; -D MESH_PACKET_LOGGING=1 ; -D MESH_DEBUG=1 build_src_filter = ${LilyGo_Techo.build_src_filter} - + - +<../examples/companion_radio/main.cpp> + + + + + + + +<../examples/companion_radio> lib_deps = ${LilyGo_Techo.lib_deps} densaugeo/base64 @ ~1.4.0 + zinggjm/GxEPD2 @ 1.6.2 diff --git a/variants/techo/variant.cpp b/variants/techo/variant.cpp index 3d3dc9c1..155aa42d 100644 --- a/variants/techo/variant.cpp +++ b/variants/techo/variant.cpp @@ -2,6 +2,10 @@ #include "wiring_constants.h" #include "wiring_digital.h" +const int MISO = PIN_SPI1_MISO; +const int MOSI = PIN_SPI1_MOSI; +const int SCK = PIN_SPI1_SCK; + const uint32_t g_ADigitalPinMap[] = { 0xff, 0xff, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, @@ -9,14 +13,22 @@ const uint32_t g_ADigitalPinMap[] = { 40, 41, 42, 43, 44, 45, 46, 47 }; -void initVariant() -{ +void initVariant() { + pinMode(PIN_PWR_EN, OUTPUT); + digitalWrite(PIN_PWR_EN, HIGH); + + pinMode(PIN_BUTTON1, INPUT_PULLUP); + pinMode(PIN_BUTTON2, INPUT_PULLUP); + pinMode(LED_RED, OUTPUT); - ledOff(LED_RED); - pinMode(LED_GREEN, OUTPUT); - ledOff(LED_GREEN); - pinMode(LED_BLUE, OUTPUT); - ledOff(LED_BLUE); + digitalWrite(LED_BLUE, HIGH); + + pinMode(PIN_TXCO, OUTPUT); + digitalWrite(PIN_TXCO, HIGH); + + // shutdown gps + pinMode(PIN_GPS_STANDBY, OUTPUT); + digitalWrite(PIN_GPS_STANDBY, LOW); } diff --git a/variants/techo/variant.h b/variants/techo/variant.h index 8fcb765e..f553ab42 100644 --- a/variants/techo/variant.h +++ b/variants/techo/variant.h @@ -42,7 +42,6 @@ #define PIN_SERIAL1_RX (41) // GPS TX #define PIN_SERIAL1_TX (40) // GPS RX - //////////////////////////////////////////////////////////////////////////////// // I2C pin definition @@ -66,6 +65,7 @@ #define LED_GREEN (33) #define LED_BLUE (14) +#define PIN_STATUS_LED LED_GREEN #define LED_BUILTIN LED_GREEN #define PIN_LED LED_BUILTIN #define LED_PIN LED_BUILTIN @@ -79,6 +79,7 @@ #define PIN_BUTTON1 (42) #define BUTTON_PIN PIN_BUTTON1 +#define PIN_USER_BTN BUTTON_PIN #define PIN_BUTTON2 (11) #define BUTTON_PIN2 PIN_BUTTON2 @@ -97,6 +98,36 @@ #define SX126X_DIO2_AS_RF_SWITCH #define SX126X_DIO3_TCXO_VOLTAGE 1.8 -#define PIN_SPI1_MISO (39) +//////////////////////////////////////////////////////////////////////////////// +// SPI1 + +#define PIN_SPI1_MISO (38) #define PIN_SPI1_MOSI (29) #define PIN_SPI1_SCK (31) + +// GxEPD2 needs that for a panel that is not even used ! +extern const int MISO; +extern const int MOSI; +extern const int SCK; + +//////////////////////////////////////////////////////////////////////////////// +// Display + +#define DISP_MISO (38) +#define DISP_MOSI (29) +#define DISP_SCLK (31) +#define DISP_CS (30) +#define DISP_DC (28) +#define DISP_RST (2) +#define DISP_BUSY (3) +#define DISP_BACKLIGHT (43) + +//////////////////////////////////////////////////////////////////////////////// +// GPS + +#define PIN_GPS_RX (41) +#define PIN_GPS_TX (40) +#define PIN_GPS_WAKEUP (34) +#define PIN_GPS_RESET (37) +#define PIN_GPS_PPS (36) +#define PIN_GPS_STANDBY (34) diff --git a/variants/xiao_nrf52/platformio.ini b/variants/xiao_nrf52/platformio.ini new file mode 100644 index 00000000..0947d86e --- /dev/null +++ b/variants/xiao_nrf52/platformio.ini @@ -0,0 +1,81 @@ +[nrf52840_xiao] +extends = nrf52_base +platform_packages = + toolchain-gccarmnoneeabi@~1.100301.0 + framework-arduinoadafruitnrf52 +board = seeed-xiao-afruitnrf52-nrf52840 +board_build.ldscript = boards/nrf52840_s140_v7.ld +build_flags = ${nrf52_base.build_flags} + -D NRF52_PLATFORM -D XIAO_NRF52 + -I lib/nrf52/s140_nrf52_7.3.0_API/include + -I lib/nrf52/s140_nrf52_7.3.0_API/include/nrf52 +lib_ignore = + BluetoothOTA + lvgl + lib5b4 +lib_deps = + ${nrf52_base.lib_deps} + rweather/Crypto @ ^0.4.0 + +[Xiao_nrf52] +extends = nrf52840_xiao +;board_build.ldscript = boards/nrf52840_s140_v7.ld +build_flags = ${nrf52840_xiao.build_flags} + -D P_LORA_TX_LED=11 + -I variants/xiao_nrf52 + -I src/helpers/nrf52 + -D RADIO_CLASS=CustomSX1262 + -D WRAPPER_CLASS=CustomSX1262Wrapper + -D LORA_TX_POWER=22 + -D SX126X_CURRENT_LIMIT=130 + -D SX126X_RX_BOOSTED_GAIN=1 +build_src_filter = ${nrf52840_xiao.build_src_filter} + + + + + +<../variants/xiao_nrf52> +debug_tool = jlink +upload_protocol = nrfutil + +[env:Xiao_nrf52_companion_radio_ble] +extends = Xiao_nrf52 +build_flags = + ${Xiao_nrf52.build_flags} + -D MAX_CONTACTS=100 + -D MAX_GROUP_CHANNELS=8 + -D BLE_PIN_CODE=123456 +; -D BLE_DEBUG_LOGGING=1 +; -D ENABLE_PRIVATE_KEY_IMPORT=1 +; -D ENABLE_PRIVATE_KEY_EXPORT=1 + -D MESH_PACKET_LOGGING=1 + -D MESH_DEBUG=1 +build_src_filter = ${Xiao_nrf52.build_src_filter} + + + +<../examples/companion_radio/main.cpp> +lib_deps = + ${Xiao_nrf52.lib_deps} + densaugeo/base64 @ ~1.4.0 + +[env:Xiao_nrf52_alt_pinout_companion_radio_ble] +extends = env:Xiao_nrf52_companion_radio_ble +build_flags = + ${env:Xiao_nrf52_companion_radio_ble.build_flags} + -D SX1262_XIAO_S3_VARIANT + +[env:Xiao_nrf52_repeater] +extends = Xiao_nrf52 +build_flags = + ${Xiao_nrf52.build_flags} + -D ADVERT_NAME='"Xiao_nrf52 Repeater"' + -D ADVERT_LAT=0.0 + -D ADVERT_LON=0.0 + -D ADMIN_PASSWORD='"password"' +; -D MESH_PACKET_LOGGING=1 +; -D MESH_DEBUG=1 +build_src_filter = ${Xiao_nrf52.build_src_filter} + +<../examples/simple_repeater/main.cpp> + +[env:Xiao_nrf52_alt_pinout_repeater] +extends = env:Xiao_nrf52_repeater +build_flags = + ${env:Xiao_nrf52_repeater.build_flags} + -D SX1262_XIAO_S3_VARIANT \ No newline at end of file diff --git a/variants/xiao_nrf52/target.cpp b/variants/xiao_nrf52/target.cpp new file mode 100644 index 00000000..0707aa39 --- /dev/null +++ b/variants/xiao_nrf52/target.cpp @@ -0,0 +1,68 @@ +#include +#include "target.h" +#include + +XiaoNrf52Board board; + +RADIO_CLASS radio = new Module(P_LORA_NSS, P_LORA_DIO_1, P_LORA_RESET, P_LORA_BUSY, SPI); + +WRAPPER_CLASS radio_driver(radio, board); + +VolatileRTCClock rtc_clock; + +#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 + + SPI.setPins(P_LORA_MISO, P_LORA_SCLK, P_LORA_MOSI); + SPI.begin(); + int status = radio.begin(LORA_FREQ, LORA_BW, LORA_SF, LORA_CR, RADIOLIB_SX126X_SYNC_WORD_PRIVATE, LORA_TX_POWER, 8, tcxo); + if (status != RADIOLIB_ERR_NONE) { + Serial.print("ERROR: radio init failed: "); + Serial.println(status); + return false; // fail + } + + radio.setCRC(1); + +#ifdef SX126X_CURRENT_LIMIT + radio.setCurrentLimit(SX126X_CURRENT_LIMIT); +#endif +#ifdef SX126X_DIO2_AS_RF_SWITCH + radio.setDio2AsRfSwitch(SX126X_DIO2_AS_RF_SWITCH); +#endif +#ifdef SX126X_RX_BOOSTED_GAIN + radio.setRxBoostedGainMode(SX126X_RX_BOOSTED_GAIN); +#endif + + return true; // success +} + +uint32_t radio_get_rng_seed() { + return radio.random(0x7FFFFFFF); +} + +void radio_set_params(float freq, float bw, uint8_t sf, uint8_t cr) { + radio.setFrequency(freq); + radio.setSpreadingFactor(sf); + radio.setBandwidth(bw); + radio.setCodingRate(cr); +} + +void radio_set_tx_power(uint8_t dbm) { + radio.setOutputPower(dbm); +} + +mesh::LocalIdentity radio_new_identity() { + RadioNoiseListener rng(radio); + return mesh::LocalIdentity(&rng); // create new random identity +} diff --git a/variants/xiao_nrf52/target.h b/variants/xiao_nrf52/target.h new file mode 100644 index 00000000..85f1ce1c --- /dev/null +++ b/variants/xiao_nrf52/target.h @@ -0,0 +1,18 @@ +#pragma once + +#define RADIOLIB_STATIC_ONLY 1 +#include +#include +#include +#include +#include + +extern XiaoNrf52Board board; +extern WRAPPER_CLASS radio_driver; +extern VolatileRTCClock rtc_clock; + +bool radio_init(); +uint32_t radio_get_rng_seed(); +void radio_set_params(float freq, float bw, uint8_t sf, uint8_t cr); +void radio_set_tx_power(uint8_t dbm); +mesh::LocalIdentity radio_new_identity(); diff --git a/variants/xiao_nrf52/variant.cpp b/variants/xiao_nrf52/variant.cpp new file mode 100644 index 00000000..16542e27 --- /dev/null +++ b/variants/xiao_nrf52/variant.cpp @@ -0,0 +1,86 @@ +#include "variant.h" +#include "wiring_constants.h" +#include "wiring_digital.h" +#include "nrf.h" + +const uint32_t g_ADigitalPinMap[] = +{ + // D0 .. D10 + 2, // D0 is P0.02 (A0) + 3, // D1 is P0.03 (A1) + 28, // D2 is P0.28 (A2) + 29, // D3 is P0.29 (A3) + 4, // D4 is P0.04 (A4,SDA) + 5, // D5 is P0.05 (A5,SCL) + 43, // D6 is P1.11 (TX) + 44, // D7 is P1.12 (RX) + 45, // D8 is P1.13 (SCK) + 46, // D9 is P1.14 (MISO) + 47, // D10 is P1.15 (MOSI) + + // LEDs + 26, // D11 is P0.26 (LED RED) + 6, // D12 is P0.06 (LED BLUE) + 30, // D13 is P0.30 (LED GREEN) + 14, // D14 is P0.14 (READ_BAT) + + // LSM6DS3TR + 40, // D15 is P1.08 (6D_PWR) + 27, // D16 is P0.27 (6D_I2C_SCL) + 7, // D17 is P0.07 (6D_I2C_SDA) + 11, // D18 is P0.11 (6D_INT1) + + // MIC + 42, // D19 is P1.10 (MIC_PWR) + 32, // D20 is P1.00 (PDM_CLK) + 16, // D21 is P0.16 (PDM_DATA) + + // BQ25100 + 13, // D22 is P0.13 (HICHG) + 17, // D23 is P0.17 (~CHG) + + // + 21, // D24 is P0.21 (QSPI_SCK) + 25, // D25 is P0.25 (QSPI_CSN) + 20, // D26 is P0.20 (QSPI_SIO_0 DI) + 24, // D27 is P0.24 (QSPI_SIO_1 DO) + 22, // D28 is P0.22 (QSPI_SIO_2 WP) + 23, // D29 is P0.23 (QSPI_SIO_3 HOLD) + + // NFC + 9, // D30 is P0.09 (NFC1) + 10, // D31 is P0.10 (NFC2) + + // VBAT + 31, // D32 is P0.31 (VBAT) +}; + +void initVariant() +{ + // Disable reading of the BAT voltage. + // https://wiki.seeedstudio.com/XIAO_BLE#q3-what-are-the-considerations-when-using-xiao-nrf52840-sense-for-battery-charging + pinMode(VBAT_ENABLE, OUTPUT); + //digitalWrite(VBAT_ENABLE, HIGH); + // This was taken from Seeed github butis not coherent with the doc, + // VBAT_ENABLE should be kept to LOW to protect P0.14, (1500/500)*(4.2-3.3)+3.3 = 3.9V > 3.6V + // This induces a 3mA current in the resistors :( but it's better than burning the nrf + digitalWrite(VBAT_ENABLE, LOW); + + // Low charging current (50mA) + // https://wiki.seeedstudio.com/XIAO_BLE#battery-charging-current + //pinMode(PIN_CHARGING_CURRENT, INPUT); + + // High charging current (100mA) + pinMode(PIN_CHARGING_CURRENT, OUTPUT); + digitalWrite(PIN_CHARGING_CURRENT, LOW); + + pinMode(PIN_QSPI_CS, OUTPUT); + digitalWrite(PIN_QSPI_CS, HIGH); + + pinMode(LED_RED, OUTPUT); + digitalWrite(LED_RED, HIGH); + pinMode(LED_GREEN, OUTPUT); + digitalWrite(LED_GREEN, HIGH); + pinMode(LED_BLUE, OUTPUT); + digitalWrite(LED_BLUE, HIGH); +} diff --git a/variants/xiao_nrf52/variant.h b/variants/xiao_nrf52/variant.h new file mode 100644 index 00000000..5d68d270 --- /dev/null +++ b/variants/xiao_nrf52/variant.h @@ -0,0 +1,149 @@ +#ifndef _SEEED_XIAO_NRF52840_H_ +#define _SEEED_XIAO_NRF52840_H_ + +/** Master clock frequency */ +#define VARIANT_MCK (64000000ul) + +#define USE_LFXO // Board uses 32khz crystal for LF +//#define USE_LFRC // Board uses RC for LF + +/*---------------------------------------------------------------------------- + * Headers + *----------------------------------------------------------------------------*/ + +#include "WVariant.h" + +#ifdef __cplusplus +extern "C" +{ +#endif // __cplusplus + +#define PINS_COUNT (33) +#define NUM_DIGITAL_PINS (33) +#define NUM_ANALOG_INPUTS (8) +#define NUM_ANALOG_OUTPUTS (0) + +// LEDs +#define PIN_LED (LED_RED) +#define LED_PWR (PINS_COUNT) +#define PIN_NEOPIXEL (PINS_COUNT) +#define NEOPIXEL_NUM (0) + +#define LED_BUILTIN (PIN_LED) + +#define LED_RED (11) +#define LED_GREEN (13) +#define LED_BLUE (12) + +#define LED_STATE_ON (1) // State when LED is litted + +// Buttons +#define PIN_BUTTON1 (PINS_COUNT) + +// Digital PINs +static const uint8_t D0 = 0 ; +static const uint8_t D1 = 1 ; +static const uint8_t D2 = 2 ; +static const uint8_t D3 = 3 ; +static const uint8_t D4 = 4 ; +static const uint8_t D5 = 5 ; +static const uint8_t D6 = 6 ; +static const uint8_t D7 = 7 ; +static const uint8_t D8 = 8 ; +static const uint8_t D9 = 9 ; +static const uint8_t D10 = 10; + +#define VBAT_ENABLE (14) // Output LOW to enable reading of the BAT voltage. + // https://wiki.seeedstudio.com/XIAO_BLE#q3-what-are-the-considerations-when-using-xiao-nrf52840-sense-for-battery-charging + +#define PIN_CHARGING_CURRENT (22) // Battery Charging current + // https://wiki.seeedstudio.com/XIAO_BLE#battery-charging-current + +// Analog pins +#define PIN_A0 (0) +#define PIN_A1 (1) +#define PIN_A2 (2) +#define PIN_A3 (3) +#define PIN_A4 (4) +#define PIN_A5 (5) +#define PIN_VBAT (32) // Read the BAT voltage. + // https://wiki.seeedstudio.com/XIAO_BLE#q3-what-are-the-considerations-when-using-xiao-nrf52840-sense-for-battery-charging + +#define BAT_NOT_CHARGING (23) // LOW when charging + +#define AREF_VOLTAGE (3.0) +#define ADC_MULTIPLIER (3.0F) // 1M, 512k divider bridge + +static const uint8_t A0 = PIN_A0; +static const uint8_t A1 = PIN_A1; +static const uint8_t A2 = PIN_A2; +static const uint8_t A3 = PIN_A3; +static const uint8_t A4 = PIN_A4; +static const uint8_t A5 = PIN_A5; + +#define ADC_RESOLUTION (12) + +// Other pins +#define PIN_NFC1 (30) +#define PIN_NFC2 (31) + +// Serial interfaces +#define PIN_SERIAL1_RX (7) +#define PIN_SERIAL1_TX (6) + +// SPI Interfaces +#define SPI_INTERFACES_COUNT (2) + +#define PIN_SPI_MISO (9) +#define PIN_SPI_MOSI (10) +#define PIN_SPI_SCK (8) + +static const uint8_t SS = D3; // NSS for sx ? +static const uint8_t MOSI = PIN_SPI_MOSI; +static const uint8_t MISO = PIN_SPI_MISO; +static const uint8_t SCK = PIN_SPI_SCK ; + +#define PIN_SPI1_MISO (25) +#define PIN_SPI1_MOSI (26) +#define PIN_SPI1_SCK (29) + +// Wire Interfaces +#define WIRE_INTERFACES_COUNT (1) + +#define PIN_WIRE_SDA (17) // 4 and 5 are used for the sx1262 ! +#define PIN_WIRE_SCL (16) // use WIRE1_SDA + +static const uint8_t SDA = PIN_WIRE_SDA; +static const uint8_t SCL = PIN_WIRE_SCL; + +//#define PIN_WIRE1_SDA (17) +//#define PIN_WIRE1_SCL (16) +#define PIN_LSM6DS3TR_C_POWER (15) +#define PIN_LSM6DS3TR_C_INT1 (18) + +// PDM Interfaces +#define PIN_PDM_PWR (19) +#define PIN_PDM_CLK (20) +#define PIN_PDM_DIN (21) + +// QSPI Pins +#define PIN_QSPI_SCK (24) +#define PIN_QSPI_CS (25) +#define PIN_QSPI_IO0 (26) +#define PIN_QSPI_IO1 (27) +#define PIN_QSPI_IO2 (28) +#define PIN_QSPI_IO3 (29) + +// On-board QSPI Flash +#define EXTERNAL_FLASH_DEVICES (P25Q16H) +#define EXTERNAL_FLASH_USE_QSPI + +#ifdef __cplusplus +} +#endif + +/*---------------------------------------------------------------------------- + * Arduino objects - C++ only + *----------------------------------------------------------------------------*/ + +#endif diff --git a/variants/xiao_s3_wio/platformio.ini b/variants/xiao_s3_wio/platformio.ini index f6275cbc..ca043f1f 100644 --- a/variants/xiao_s3_wio/platformio.ini +++ b/variants/xiao_s3_wio/platformio.ini @@ -13,6 +13,8 @@ build_flags = ${esp32_base.build_flags} -D P_LORA_SCLK=7 -D P_LORA_MISO=8 -D P_LORA_MOSI=9 + -D PIN_USER_BTN=21 + -D PIN_STATUS_LED=48 -D SX126X_DIO2_AS_RF_SWITCH=true -D SX126X_DIO3_TCXO_VOLTAGE=1.8 -D SX126X_CURRENT_LIMIT=130 @@ -105,3 +107,25 @@ build_src_filter = ${Xiao_S3_WIO.build_src_filter} lib_deps = ${Xiao_S3_WIO.lib_deps} densaugeo/base64 @ ~1.4.0 + +[env:Xiao_S3_WIO_expansion_companion_radio_ble] +extends = Xiao_S3_WIO +build_flags = + ${Xiao_S3_WIO.build_flags} + -D MAX_CONTACTS=100 + -D MAX_GROUP_CHANNELS=8 + -D BLE_PIN_CODE=123456 + -D DISPLAY_CLASS=SSD1306Display +; -D BLE_DEBUG_LOGGING=1 +; -D ENABLE_PRIVATE_KEY_IMPORT=1 +; -D ENABLE_PRIVATE_KEY_EXPORT=1 +; -D MESH_PACKET_LOGGING=1 +; -D MESH_DEBUG=1 +build_src_filter = ${Xiao_S3_WIO.build_src_filter} + + + + + +<../examples/companion_radio> +lib_deps = + ${Xiao_S3_WIO.lib_deps} + densaugeo/base64 @ ~1.4.0 + adafruit/Adafruit SSD1306 @ ^2.5.13 diff --git a/variants/xiao_s3_wio/target.cpp b/variants/xiao_s3_wio/target.cpp index 8e8b8e75..ddb700b7 100644 --- a/variants/xiao_s3_wio/target.cpp +++ b/variants/xiao_s3_wio/target.cpp @@ -22,7 +22,9 @@ AutoDiscoverRTCClock rtc_clock(fallback_clock); bool radio_init() { fallback_clock.begin(); rtc_clock.begin(Wire); - + pinMode(21, INPUT); + pinMode(48, OUTPUT); + #ifdef SX126X_DIO3_TCXO_VOLTAGE float tcxo = SX126X_DIO3_TCXO_VOLTAGE; #else